forked from organicmaps/organicmaps
[AND] Merge ext libs. Removed unused sources.
interm interm
This commit is contained in:
parent
9defbe43bd
commit
af1cc929bc
1556 changed files with 13 additions and 68631 deletions
7
android/3rd_party/HoloEverywhere/LICENSE
vendored
7
android/3rd_party/HoloEverywhere/LICENSE
vendored
|
@ -1,7 +0,0 @@
|
|||
Copyright (C) 2013 Sergey Shatunov
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
52
android/3rd_party/HoloEverywhere/README.md
vendored
52
android/3rd_party/HoloEverywhere/README.md
vendored
|
@ -1,52 +0,0 @@
|
|||

|
||||
|
||||
[](https://travis-ci.org/Prototik/HoloEverywhere)
|
||||
|
||||
## What is it?
|
||||
Bringing Holo Theme from Android 4.1 to 2.1 and above.
|
||||
## Links
|
||||
[][Play Store]
|
||||
[][Donate]
|
||||
|
||||
## How to use?
|
||||
### [Eclipse](https://github.com/Prototik/HoloEverywhere/wiki/Import-in-IDE#eclipse)
|
||||
### [Eclipse + Maven](https://github.com/Prototik/HoloEverywhere/wiki/Import-in-IDE#eclipse--maven)
|
||||
### [IntelliJ IDEA](https://github.com/Prototik/HoloEverywhere/wiki/Import-in-IDE#intellij-idea)
|
||||
|
||||
## Screenshots
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## Featured implementations
|
||||
* [Project Euler](https://play.google.com/store/apps/details?id=ie.cathalcoffey.android.projecteuler)
|
||||
* [Meditation Assistant](https://play.google.com/store/apps/details?id=sh.ftp.rocketninelabs.meditationassistant)
|
||||
* [Ragnabase MVP](https://play.google.com/store/apps/details?id=com.ragnabase.mvp)
|
||||
* [noodles - To Do List](https://play.google.com/store/apps/details?id=com.makeramen.noodles)
|
||||
|
||||
Write to [Sergey](mailto:prototypegamez@gmail.com) for add your application to this list.
|
||||
|
||||
## Contact
|
||||
|
||||
Sergey:
|
||||
* [Email](mailto:prototypegamez@gmail.com "Send email to Sergey")
|
||||
* [Google Plus](https://plus.google.com/103272077758668000975/posts "Google Plus")
|
||||
* [Habrahabr](http://habrahabr.ru/users/prototik/)
|
||||
|
||||
Christophe:
|
||||
* [Google Plus](https://plus.google.com/108315424589085456181/posts "Google Plus")
|
||||
|
||||
## License
|
||||
MIT License, full text of license see [here][License]
|
||||
|
||||
[Play Store]: https://play.google.com/store/apps/details?id=org.holoeverywhere.demo "Play Store"
|
||||
[Donate]: https://www.paypal.com/cgi-bin/webscr?cmd=_donations&business=X7E7U7HNR36YN&lc=US&item_name=HoloEverywhere¤cy_code=USD&bn=PP%2dDonationsBF%3adonate_button%2epng%3aNonHosted "Donate"
|
||||
[Build with Maven]: https://github.com/Prototik/HoloEverywhere/wiki/Maven "Build with maven"
|
||||
[License]: https://raw.github.com/Prototik/HoloEverywhere/master/LICENSE "LGPLv3"
|
113
android/3rd_party/HoloEverywhere/checkstyle.xml
vendored
113
android/3rd_party/HoloEverywhere/checkstyle.xml
vendored
|
@ -1,113 +0,0 @@
|
|||
<?xml version="1.0"?>
|
||||
<!DOCTYPE module PUBLIC
|
||||
"-//Puppy Crawl//DTD Check Configuration 1.2//EN"
|
||||
"http://www.puppycrawl.com/dtds/configuration_1_2.dtd">
|
||||
<module name="Checker">
|
||||
<module name="NewlineAtEndOfFile" />
|
||||
<module name="FileLength" />
|
||||
<module name="FileTabCharacter" />
|
||||
|
||||
<module name="TreeWalker">
|
||||
<property name="cacheFile" value="${checkstyle.cache.file}" />
|
||||
|
||||
<!-- Checks for Javadoc comments. -->
|
||||
<!-- See http://checkstyle.sf.net/config_javadoc.html -->
|
||||
<!--module name="JavadocMethod"/ -->
|
||||
<!--module name="JavadocType"/ -->
|
||||
<!--module name="JavadocVariable"/ -->
|
||||
<!--module name="JavadocStyle"/ -->
|
||||
|
||||
|
||||
<!-- Checks for Naming Conventions. -->
|
||||
<!-- See http://checkstyle.sf.net/config_naming.html -->
|
||||
<!--module name="ConstantName"/ -->
|
||||
<!--module name="LocalFinalVariableName"/ -->
|
||||
<!--module name="LocalVariableName"/ -->
|
||||
<module name="MemberName" />
|
||||
<!--module name="MethodName"/ -->
|
||||
<module name="PackageName" />
|
||||
<!--module name="ParameterName"/ -->
|
||||
<!--module name="StaticVariableName"/ -->
|
||||
<!--module name="TypeName"/ -->
|
||||
|
||||
|
||||
<!-- Checks for imports -->
|
||||
<!-- See http://checkstyle.sf.net/config_import.html -->
|
||||
<module name="AvoidStarImport" />
|
||||
<module name="IllegalImport" /> <!-- defaults to sun.* packages -->
|
||||
<module name="RedundantImport" />
|
||||
<module name="UnusedImports" />
|
||||
|
||||
|
||||
<!-- Checks for Size Violations. -->
|
||||
<!-- See http://checkstyle.sf.net/config_sizes.html -->
|
||||
<!--module name="LineLength"/ -->
|
||||
<!--module name="MethodLength"/ -->
|
||||
<!--module name="ParameterNumber"/ -->
|
||||
|
||||
|
||||
<!-- Checks for whitespace -->
|
||||
<!-- See http://checkstyle.sf.net/config_whitespace.html -->
|
||||
<!--module name="EmptyForIteratorPad"/ -->
|
||||
<!--module name="MethodParamPad"/ -->
|
||||
<!--module name="NoWhitespaceAfter"/ -->
|
||||
<!--module name="NoWhitespaceBefore"/ -->
|
||||
<!--module name="OperatorWrap"/ -->
|
||||
<!--module name="ParenPad"/ -->
|
||||
<!--module name="TypecastParenPad"/ -->
|
||||
<!--module name="WhitespaceAfter"/ -->
|
||||
<!--module name="WhitespaceAround"/ -->
|
||||
|
||||
|
||||
<!-- Modifier Checks -->
|
||||
<!-- See http://checkstyle.sf.net/config_modifiers.html -->
|
||||
<!--module name="ModifierOrder"/ -->
|
||||
<!--module name="RedundantModifier"/ -->
|
||||
|
||||
|
||||
<!-- Checks for blocks. You know, those {}'s -->
|
||||
<!-- See http://checkstyle.sf.net/config_blocks.html -->
|
||||
<!--module name="AvoidNestedBlocks"/ -->
|
||||
<!--module name="EmptyBlock"/ -->
|
||||
<!--module name="LeftCurly"/ -->
|
||||
<!--module name="NeedBraces"/ -->
|
||||
<!--module name="RightCurly"/ -->
|
||||
|
||||
|
||||
<!-- Checks for common coding problems -->
|
||||
<!-- See http://checkstyle.sf.net/config_coding.html -->
|
||||
<!--module name="AvoidInlineConditionals"/ -->
|
||||
<!--module name="EmptyStatement"/ -->
|
||||
<!--module name="EqualsHashCode"/ -->
|
||||
<!--module name="HiddenField"/ -->
|
||||
<!--module name="IllegalInstantiation"/ -->
|
||||
<!--module name="InnerAssignment"/ -->
|
||||
<!--module name="MagicNumber"/ -->
|
||||
<!--module name="MissingSwitchDefault"/ -->
|
||||
<!--module name="RedundantThrows" /-->
|
||||
<!--module name="SimplifyBooleanExpression"/ -->
|
||||
<!--module name="SimplifyBooleanReturn"/ -->
|
||||
<module name="StringLiteralEquality" />
|
||||
<module name="CovariantEquals" />
|
||||
<!--module name="NoClone"/ -->
|
||||
<module name="NoFinalizer" />
|
||||
<module name="PackageDeclaration" />
|
||||
<!--module name="FallThrough"/ -->
|
||||
|
||||
<!-- Checks for class design -->
|
||||
<!-- See http://checkstyle.sf.net/config_design.html -->
|
||||
<!--module name="DesignForExtension"/ -->
|
||||
<!--module name="FinalClass"/ -->
|
||||
<!--module name="HideUtilityClassConstructor"/ -->
|
||||
<!--module name="InterfaceIsType"/ -->
|
||||
<!--module name="VisibilityModifier"/ -->
|
||||
|
||||
|
||||
<!-- Miscellaneous other checks. -->
|
||||
<!-- See http://checkstyle.sf.net/config_misc.html -->
|
||||
<!--module name="ArrayTypeStyle"/ -->
|
||||
<!--module name="FinalParameters"/ -->
|
||||
<!--module name="TodoComment"/ -->
|
||||
<module name="UpperEll" />
|
||||
</module>
|
||||
</module>
|
|
@ -1,18 +0,0 @@
|
|||
language: java
|
||||
|
||||
branches:
|
||||
excludes:
|
||||
- gh-pages
|
||||
|
||||
notifications:
|
||||
email: false
|
||||
|
||||
before_install:
|
||||
- wget http://dl.google.com/android/android-sdk_r20.0.3-linux.tgz
|
||||
- tar -zxf android-sdk_r20.0.3-linux.tgz
|
||||
- export ANDROID_HOME=~/builds/JakeWharton/ActionBarSherlock/android-sdk-linux
|
||||
- export PATH=${PATH}:${ANDROID_HOME}/tools:${ANDROID_HOME}/platform-tools
|
||||
- TOOLS=$(android list sdk --no-ui | grep "Android SDK Platform-tools" | cut -d"-" -f1)
|
||||
- android update sdk --filter "$TOOLS" --no-ui --force
|
||||
- SDK=$(android list sdk --no-ui | grep ", API 14," | cut -d"-" -f1)
|
||||
- android update sdk --filter "$SDK" --no-ui --force
|
|
@ -1,496 +0,0 @@
|
|||
Change Log
|
||||
===============================================================================
|
||||
|
||||
Version 4.3.1 *(2013-04-28)*
|
||||
----------------------------
|
||||
|
||||
* Fix: Importing library into Eclipse as a Maven module now works correctly.
|
||||
* Prevent dispatching touch events to both action bar and content view on API
|
||||
11 and up.
|
||||
* Add Hebrew and Brazillian translations to i18n module.
|
||||
|
||||
|
||||
Version 4.3.0 *(2013-04-15)*
|
||||
----------------------------
|
||||
|
||||
* New: FEST module for testing ActionBarSherlock classes.
|
||||
* New: i18n module for including internationalized strings used by actionbar.
|
||||
* Removed dialog themes.
|
||||
* Fix: `SearchView` suggestions now work properly.
|
||||
* Fix: Prevent rare NPE when restoring state on pre-Honeycomb devices.
|
||||
* Fix: Correct behavior of `IcsColorDrawable`'s `setAlpha` method.
|
||||
* Fix: Handle cases where `Locale.ROOT` is not present on pre-Honeycomb.
|
||||
* Fix: Correct tab measurement edge-case on pre-Honeycomb.
|
||||
* Use custom Toast layout to ensure consistent look and feel.
|
||||
* Fix: Prevent monkey runners from uselessly crashing.
|
||||
* Fix: Do not hold on to old menu items after a call to `invalidateOptionsMenu`.
|
||||
* Fix: Ensure `ShareActionProvider` works when only one intent is available.
|
||||
* Fix: Scroll list navigation to the selected item when opened.
|
||||
|
||||
|
||||
Version 4.2.0 *(2012-10-07)*
|
||||
----------------------------
|
||||
|
||||
**Maven `artifactId` is now 'actionbarsherlock'.**
|
||||
|
||||
Note: The `.Dialog` themes are now deprecated. These will be removed in a future
|
||||
version of the library.
|
||||
|
||||
* Add `SearchView` widget for standard search interaction (API 8+ only)
|
||||
* Fix: `ShareActionProvider` in the split action bar no longer fills the entire
|
||||
screen.
|
||||
* Fix: `ShareActionProvider` now does file I/O on a background thread.
|
||||
* Fix: Automatically correct `ColorDrawable` not respecting bounds when used as
|
||||
a stacked background.
|
||||
* Fix: Ensure fragments collection is present before dispatching events.
|
||||
* Fix: XML-defined `onClick` searches the correct context for the declared
|
||||
method.
|
||||
* Fix: Ensure action mode start/finish callbacks are invoked on the activity
|
||||
for the native action bar.
|
||||
* Fix: Allow tab callbacks to have a fragment transaction instance for any
|
||||
`FragmentActivity`.
|
||||
* Fix: Ensure `CollapsibleActionView` callbacks are dispatched in both native
|
||||
and compatbility action bars.
|
||||
* Fix: Remove `.ForceOverflow` themes. These never should have been included.
|
||||
|
||||
|
||||
Version 4.1.0 *(2012-05-17)*
|
||||
----------------------------
|
||||
|
||||
* Fix: Altered technique used for menu event dispatching through the fragment
|
||||
manager for greater control.
|
||||
* Fix: Do not dispatch menu creation event if the activity has been destroyed.
|
||||
* Fix: Correct potential `NullPointerException` when expanding an action item.
|
||||
* Fix: Correct potential `NullPointerException` when the hardware menu key was
|
||||
pressed in an activity that is forcing the overflow menu.
|
||||
* Fix: Do not set a listener on the native action bar tab wrapper unless a
|
||||
compatibility listener has been set.
|
||||
* Fix: Ensure the compatibility animation framework is always available on
|
||||
views even if they were previously detached from the view hierarchy.
|
||||
|
||||
|
||||
Version 4.0.2 *(2012-04-15)*
|
||||
----------------------------
|
||||
|
||||
* Upgrade to r7 support library.
|
||||
* Fix: Do not trigger menu creation after `onCreate` if activity is finishing.
|
||||
* Fix: Prevent overflow from displaying if there are no overflow action items.
|
||||
* Fix: Long-pressing menu key no longer triggers overflow.
|
||||
* Fix: Use proper tab state-list drawable to mimic ICS.
|
||||
* Fix: Ensure dispatching menu creation and preparation to fragments can
|
||||
properly return `false` when appropriate to avoid rendering artifacts.
|
||||
* Fix: Properly save and fetch action mode tag on ICS.
|
||||
* Fix: Add missing density-specific resources for certain asssets and remove
|
||||
unused assets.
|
||||
|
||||
|
||||
Version 4.0.1 *(2012-03-25)*
|
||||
----------------------------
|
||||
|
||||
* Add `ShareActionProvider` widget for use as action items.
|
||||
* Re-add 'Styled' sample to provide a more comprehensive theming example.
|
||||
* Fix: Do not dispatch options item selection to fragments if the activity
|
||||
handles the callback.
|
||||
* Fix: Prevent menu key from opening the overflow menu when an action mode is
|
||||
currently displayed.
|
||||
* Fix: Ensure fragment transaction instance is not `null` on initial tab
|
||||
selection callback.
|
||||
* Fix: Displaying an action mode while using stacked tab navigation no longer
|
||||
throws an exception.
|
||||
* Fix: Using expandable action item callbacks no longer results in a possible
|
||||
exception on older devices.
|
||||
|
||||
|
||||
Version 4.0.0 *(2012-03-07)*
|
||||
----------------------------
|
||||
|
||||
Complete rewrite of the library to backport the Android 4.0 action bar.
|
||||
|
||||
* The minimum supported version of Android is now 2.1 (API 7).
|
||||
* New base activities are provided (e.g., `SherlockActivity` and
|
||||
`SherlockFragmentActivity`) which extend from the native activities.
|
||||
* The support library sources are no longer included in the library. You must
|
||||
include `android-support-v4.jar` in your project separately.
|
||||
* Theming now mirrors that of the native action bar through the use of multiple
|
||||
styles rather than through `ab`- and `am`-prefixed attributes in the theme.
|
||||
* The action bar can be statically attached to an activity view without the
|
||||
requirement of using one of the provided base activities.
|
||||
|
||||
|
||||
Version 3.5.1 *(2012-01-03)*
|
||||
----------------------------
|
||||
|
||||
* Fix: `NullPointerException` in `FragmentManager` can no longer occur when an
|
||||
attempt is being made to save to a `Bundle` that has not yet been created.
|
||||
* Fix: Pre-3.0 action item submenu dialogs now properly dismiss themselves when
|
||||
an item of theirs is selected.
|
||||
|
||||
|
||||
Version 3.5.0 *(2011-12-18)*
|
||||
----------------------------
|
||||
|
||||
* Library now uses the `r6` version of the compatibility library for its base.
|
||||
Ice Cream Sandwich-specific implementations are currently disabled, however,
|
||||
but will be added in a future version of the library.
|
||||
|
||||
`MenuCompat`, `MenuItemCompat`, and `ActivityCompat` have be added back in
|
||||
to ease transition to this library but all their methods and the classes
|
||||
themselves have been deprecated.
|
||||
* Rewritten menu and action item support from Ice Cream Sandwich.
|
||||
|
||||
* Removed the need for the custom `Window.FEATURE_ACTION_ITEM_TEXT` flag.
|
||||
You should now use the `showAsAction` attribute and/or the
|
||||
`setShowAsAction(int)` method on each `MenuItem` to control whether or
|
||||
not text is shown
|
||||
* Action item dividers are now added automatically only when necessary
|
||||
to distinguish possible confusion between action items.
|
||||
* Fix: Action views now properly size themselves within the bounded space
|
||||
of the menu.
|
||||
|
||||
* Fix: List navigation no longer becomes unusable on certain device
|
||||
configurations.
|
||||
* Fix: `SubMenu`'s `findItem(int)` method now properly returns the support
|
||||
version of `MenuItem`.
|
||||
* Fix: Invisible sub-menu items are no longer shown on the pre-3.0 popup list.
|
||||
|
||||
|
||||
Version 3.4.2 *(2001-11-09)*
|
||||
----------------------------
|
||||
|
||||
* Fix: Stacked action bar now properly sets the tab bar background based on
|
||||
the theme.
|
||||
|
||||
|
||||
Version 3.4.1 *(2011-11-09)*
|
||||
----------------------------
|
||||
|
||||
* The `makeFragmentName` method in `FragmentPagerAdapter` has been changed to
|
||||
`public` scope to allow for easier access to your fragments that it is
|
||||
managing.
|
||||
* Action bar will now animate when calling `show()` or `hide()`.
|
||||
* `SherlockPreferenceActivity` now provides full fragment and loader support.
|
||||
* Examples for the plugins are now in their own sample application.
|
||||
* Fix: Home icon no longer erroneously clipped when it exceeds the size of the
|
||||
action bar.
|
||||
* Fix: Tabs will now scroll horizontally to mimic the native action bar
|
||||
behavior.
|
||||
* Fix: Plugins now properly DO NOT inline their `R.java` integer constants.
|
||||
* Fix: Tabs below the action bar are now styled with a default background so
|
||||
that they do not incorrectly inherit an applied background unless explicity
|
||||
declared.
|
||||
|
||||
|
||||
Version 3.4.0 *(2011-10-30)*
|
||||
----------------------------
|
||||
|
||||
* Library now uses the `r4` version of the compatibility library for its base.
|
||||
Ice Cream Sandwich-specific implementations are currently disabled, however,
|
||||
but will be added in a future version of the library.
|
||||
* Context menu callbacks now use the support version of `MenuItem` to maintain
|
||||
consistency.
|
||||
* Added preference plugin which provides an action bar enhanced preference
|
||||
screen.
|
||||
* Fix: `abHomeLayout` theme attribute is now honored.
|
||||
* Fix: `onPrepareOptionsMenu` is now properly dispatched upon menu
|
||||
invalidation.
|
||||
|
||||
|
||||
Version 3.3.1 *(2011-10-20)*
|
||||
----------------------------
|
||||
|
||||
ADT 14 is now required. Maven 3 is required if building from the command line.
|
||||
|
||||
* XML-defined `onClick` attributes will now check for an `onClick` method that
|
||||
takes an `android.support.v4.view.MenuItem` instance.
|
||||
* Tabs on medium screens in landscape now display inline rather than below the
|
||||
action bar to mirror how Android 4.0 behaves with the same configuration.
|
||||
* Fix: Menu inflater properly checks activity context for `onClick` method
|
||||
declared in the XML.
|
||||
* Fix: Dialog fragment properly saves its `showDialog` state when not being
|
||||
used as a popup.
|
||||
* Fix: Return `-1` when in tab navigation but no tab is selected. This brings
|
||||
the library in line with the post-3.0 behavior.
|
||||
* Fix: Removing a menu group no longer throws an `IndexOutOfBoundsException`.
|
||||
* Fix: `getSelectedTab` and `getTabAt` no longer throw `NullPointerException`s
|
||||
on post-3.0 when no tab was selected or no tab existed at the specified
|
||||
position, respectively.
|
||||
* Fix: `findFragmentById` now properly returns fragments attached to
|
||||
`android.R.id.content` when run on pre-3.0 devices.
|
||||
|
||||
|
||||
Version 3.3.0 *(2011-10-11)*
|
||||
----------------------------
|
||||
|
||||
* Tabs are now displayed below the action bar on all medium-screen devices and
|
||||
portrait large-screen devices.
|
||||
* Fix: Dialog fragments no longer throw an `IllegalStateException` when being
|
||||
used as a regular fragment (i.e., not as a popup). See
|
||||
[StackOverflow](http://stackoverflow.com/questions/5637894/dialogfragments-with-devices-api-level-11/7560686#7560686)
|
||||
for more information.
|
||||
* Fix: Popping a fragment off of the back stack now properly assigns its parent
|
||||
activity.
|
||||
* Fix: An activity result no longer causes a `NullPointerException` when the
|
||||
target fragment no longer exists.
|
||||
* Fix: Action item dividers are now properly initially hidden when their
|
||||
associated action items are as well.
|
||||
|
||||
|
||||
Version 3.2.3 *(2011-09-16)*
|
||||
----------------------------
|
||||
|
||||
* Fix: Fragments in a `ViewPager` that contributed items to the options menu
|
||||
were caught in a race condition causing inconsistent results when a new page
|
||||
was selected. This regression was introduced in version 3.2.2.
|
||||
|
||||
|
||||
Version 3.2.2 *(2011-09-15)*
|
||||
----------------------------
|
||||
|
||||
* Fix: Side-effects related to using `FragmentMapActivity` due to how it was
|
||||
referencing resources from the main library.
|
||||
* Fix: Fragments adjacent to the currently selected fragment in a `ViewPager`
|
||||
no longer receive context menu events.
|
||||
* Fix: Eliminate exception when inflating context menus on 3.0+ when using
|
||||
`getMenuInflater()`.
|
||||
* Fix: `ViewPager` now determines whether or not an activity menu invalidation
|
||||
is required independently of whether or not fragments were created or
|
||||
destroyed. This should fix an edge case where an activity with a `ViewPager`
|
||||
containing only two fragments would not get its menu properly invalidated.
|
||||
|
||||
|
||||
Version 3.2.1 *(2011-09-12)*
|
||||
----------------------------
|
||||
|
||||
* Fix: Action mode API incorrectly using the native `Menu` and `MenuItem`
|
||||
classes causing an easy pitfall for `ClassCastExceptions`.
|
||||
* Fix: Large action bar backgrounds increasing the size beyond that alloted in
|
||||
the theme.
|
||||
|
||||
|
||||
Version 3.2.0 *(2011-09-05)*
|
||||
----------------------------
|
||||
|
||||
* Added support for `MapView` and the Google APIs through the use of
|
||||
`FragmentMapActivity`. If you are using a map within a fragment you must
|
||||
ensure it is always attached to an activity which extends from this new base
|
||||
class.
|
||||
|
||||
Since supporting maps requires compiling against the Google APIs, this
|
||||
functionality is implemented in the form of a plugin which is to be used
|
||||
alongside the normal library. You can choose to add it as an additional
|
||||
library project or by including it as a `.jar`. Maven users may simply
|
||||
include the additional dependency (artifactId: `plugin-maps`).
|
||||
* Fix: Fragments adjacent to the currently selected fragment in a `ViewPager`
|
||||
no longer contribute to the activity menu.
|
||||
* `ActionBar.Tab` has been changed from an interface to an abstract class to
|
||||
mirror its native counterpart.
|
||||
|
||||
|
||||
Version 3.1.3 *(2011-08-14)*
|
||||
----------------------------
|
||||
|
||||
* Renamed all resources to be prefixed with `abs__` to avoid conflicts when
|
||||
including in your project.
|
||||
* Fix: Action bar background being set on two views causing artifacts to remain
|
||||
on screen when the action bar was hidden.
|
||||
* Fix: Incorrect sub-menu item being selected by default when the sub-menu was
|
||||
triggered from the native options menu on pre-3.0.
|
||||
* Fix: `MenuItem.setVisible` now properly updates the associated action item and
|
||||
native menu item visible state.
|
||||
* Fix: Adding items to a menu now honors its ordering and category.
|
||||
* Fix: Fragment options item selected callback now uses the proper version of
|
||||
`MenuItem`.
|
||||
|
||||
|
||||
Version 3.1.2 *(2011-08-07)*
|
||||
----------------------------
|
||||
|
||||
* Fix: `MenuItem.getMenuInfo()` was throwing runtime exception. Will now just
|
||||
return `null`.
|
||||
* Fix: Dragging over a `WebView` contained in a `ViewPager` would not register.
|
||||
* Fix: Inflation of context menu incorrectly being handled by the custom menu
|
||||
inflater for the library.
|
||||
|
||||
|
||||
Version 3.1.1 *(2011-07-31)*
|
||||
----------------------------
|
||||
|
||||
* Fix: `MenuItem.getSubMenu` now returns a support instance rather than a
|
||||
native instance.
|
||||
* Fix: Fragment methods `onAttach` and `onInflate` incorrectly regressed to use
|
||||
`Activity` instead of a `FragmentActivity` in their method signatures.
|
||||
* Fix: Retained fragments not being re-attached on pre-3.0 when attached to
|
||||
`android.R.id.content` upon activity recreation.
|
||||
* Fix: `onPrepareOptionsMenu` not dispatched to fragments. This still will only
|
||||
occur if the activity method returns true (which is the default).
|
||||
* Fix: `Menu.findItem` not returning `null` when the item was not found on
|
||||
Android 3.0+.
|
||||
|
||||
|
||||
Version 3.1.0 *(2011-07-22)*
|
||||
----------------------------
|
||||
|
||||
Due to shortcomings in the Android theming system, a small change must be made
|
||||
in how this library handles themes. If you were using a custom style for
|
||||
`actionBarStyle` you must now specify its attributes in the root of the theme
|
||||
and prefix them with 'ab'.
|
||||
|
||||
You can see an example of this in the `SherlockCustom` theme in
|
||||
`samples/demos/res/values/styles.xml`.
|
||||
|
||||
* Library now uses the `r3` version of the compatibility library for its base.
|
||||
* `actionBarStyle` is no longer a valid theme attribute (see note above).
|
||||
* Added the demo project included with the new compatibility library under
|
||||
`samples/demos/` and merged in the old 'featuredemo'.
|
||||
* Dividers are now shown on pre-3.0 devices between all action items.
|
||||
* `Window.FEATURE_ACTION_BAR_OVERLAY` is now honored on pre-3.0 devices.
|
||||
* Inflation of XML menu resources will now honor `android:actionLayout` and
|
||||
`android:actionViewClass` attributes.
|
||||
* Buttons for displaying the determinate and indeterminate progress bars have
|
||||
been added to the feature toggle demo.
|
||||
* Added support for indeterminate progress bar. Due to the `final` modifier on
|
||||
the native type, you must use `setIndeterminateProgressBarVisibility(Boolean)`
|
||||
and pass `Boolean.TRUE` or `Boolean.FALSE`.
|
||||
* Fix: `MenuBuilder#removeItem(int)` and `MenuBuilder#findItem(int)` throwing
|
||||
`IndexOutOfBoundsException`s when the item was not found.
|
||||
* Fix: Theme attributes for home item data (e.g., icon, logo) will not be
|
||||
overwritten by the special `MenuItem` instance for home.
|
||||
* Fix: Native strings can now be specified for an XML menu `<item>` in
|
||||
`android:title` and `android:titleCondensed`.
|
||||
* `Window.FEATURE_ENABLE_ACTION_BAR_WATSON_TEXT` is now
|
||||
`Window.FEATURE_ACTION_BAR_ITEM_TEXT`.
|
||||
* `Widget.Sherlock.Spinner.DropDown.ActionBar` and
|
||||
`Widget.Sherlock.Light.Spinner.DropDown.ActionBar` styles are now
|
||||
`Widget.Sherlock.Spinner` and `Widget.Sherlock.Light.Spinner`, respectively.
|
||||
* `Widget.Sherlock.ActionBarView_TabXXX` styles are now
|
||||
`Widget.Sherlock.ActionBar.TabXXX`.
|
||||
|
||||
|
||||
Version 3.0.3 *(2011-07-17)*
|
||||
----------------------------
|
||||
|
||||
This version is a hotfix for incompatibilities introduced with the SDKs for
|
||||
3.1 r2 and 3.2 r1. Due to unavoidable changes in the underlying SDK, the library
|
||||
must now be compiled against API level 13.
|
||||
|
||||
* `actionModeStyle` and `actionModePopupWindowStyle` are no longer valid theme
|
||||
attributes.
|
||||
|
||||
|
||||
Version 3.0.2 *(2011-06-23)*
|
||||
----------------------------
|
||||
|
||||
* Sub-menus for action items are now shown in a list dialog.
|
||||
* Moved certain classes to the `com.actionbarsherlock.internal` package which
|
||||
were not meant for public consumption. Despite being given `public` scope in
|
||||
this new package, these classes should **NOT** be used under any circumstances
|
||||
as their API can be considered highly volatile and is subject to change often
|
||||
and without warning.
|
||||
|
||||
|
||||
Version 3.0.1 *(2011-06-08)*
|
||||
----------------------------
|
||||
|
||||
* Fix: `onOptionsItemSelected()` not being called in fragments if the activity
|
||||
version returns `false`.
|
||||
* Fix: `onCreateOptionsMenu()` not being called in fragments on Android 3.0+.
|
||||
* New: Enable action item text display on pre-Android 3.0 by calling
|
||||
`requestWindowFeature` with `Window.FEATURE_ENABLE_ACTION_BAR_WATSON_TEXT`.
|
||||
* Fix: `setCustomView()` no longer automatically enables the custom view on
|
||||
pre-3.0. You must call `setDisplayShowCustomEnabled()` in order to display
|
||||
the view.
|
||||
|
||||
|
||||
Version 3.0.0 *(2011-06-05)*
|
||||
----------------------------
|
||||
|
||||
The API has been rewritten to mimic that of the native action bar. As a result,
|
||||
usage now only requires changing a few imports to use the support versions
|
||||
of classes and calling `getSupportActionBar()`. See the README for more info.
|
||||
|
||||
The rewrite necessitated tight interaction with the
|
||||
[compatibility library](http://android-developers.blogspot.com/2011/03/fragments-for-all.html)
|
||||
to the point where its sources are now included. You are no longer required to
|
||||
have the standalone `.jar` file.
|
||||
|
||||
Also included is a default custom action bar for use by default on pre-3.0
|
||||
devices. This custom implementation is based off of Johan Nilsson's
|
||||
[Android-ActionBar](https://github.com/johannilsson/android-actionbar) and the
|
||||
[work that I have done](https://github.com/johannilsson/android-actionbar/pull/25)
|
||||
on it.
|
||||
|
||||
More details are available at http://actionbarsherlock.com
|
||||
|
||||
|
||||
Version 2.1.1 *(2011-03-21)*
|
||||
----------------------------
|
||||
|
||||
**No changes to library code.**
|
||||
|
||||
* Moved library to the root of the repository.
|
||||
* Added `samples/dependencies.py` script to automatically download the needed
|
||||
dependencies for the sample projects.
|
||||
|
||||
|
||||
Version 2.1.0 *(2011-03-21)*
|
||||
----------------------------
|
||||
|
||||
**WARNING**: The
|
||||
[Android Compatibility Library (v4)](http://android-developers.blogspot.com/2011/03/fragments-for-all.html)
|
||||
is now required.
|
||||
|
||||
* Added `ActionBarSherlock.Activity`, `ActionBarSherlock.FragmentActivity`,
|
||||
and `ActionBarSherlock.ListActivity` for extension by implementing
|
||||
activities, the latter of which is deprecated. This affords a much tighter
|
||||
integration and allows for the use of other new features listed below.
|
||||
* New API method: `layout(Fragment)` will use the fragment argument as the
|
||||
content to the activity.
|
||||
* New API method: `menu(int)` allows for the inflation of menu XMLs from a
|
||||
resource. For the non-native implementation, the XML can be inflated to a
|
||||
custom Menu which can then be applied appropriately to the third-party
|
||||
action bar. Sub-menus are also supported. Third-party action bar handlers
|
||||
should implement `ActionBarSherlock.HasMenu` for this functionality. *This
|
||||
feature requires that activities extend from one of the provided activity
|
||||
base classes.*
|
||||
* New API method: `homeAsUp(boolean)`. This mimics the native method
|
||||
`setDisplayHomeAsUpEnalbed` on the native action bar. Third-party action bar
|
||||
handlers should implement `ActionBarSherlock.HasHomeAsUp` for this
|
||||
functionality.
|
||||
* New API method: `useLogo(boolean)` will trigger the action bar to hide the
|
||||
application icon/home button and title and show a larger logo representing
|
||||
the application. Third-party action bar handlers should implement
|
||||
`ActionBarSherlock.HasLogo` for this functionality.
|
||||
* New API method: `listNavigation(SpinnerAdapter, OnNavigationListener)`. Tells
|
||||
the action bar to use drop-down style navigation with the specified list of
|
||||
items and callback listener. Third-party action bar handlers should
|
||||
implement `ActionBarSherlock.HasListNavigation` for this functionality.
|
||||
* Javadocs are now available at
|
||||
[jakewharton.github.com/ActionBarSherlock](http://jakewharton.github.com/ActionBarSherlock/).
|
||||
* A standalone JAR is now available via the
|
||||
[GitHub downloads page](https://github.com/JakeWharton/ActionBarSherlock/downloads)
|
||||
or in my
|
||||
[personal maven repository](http://r.jakewharton.com/maven/)
|
||||
as `com.jakewharton:android-actionbarsherlock:2.1.0`.
|
||||
|
||||
|
||||
Version 2.0.1 *(2011-03-11)*
|
||||
----------------------------
|
||||
|
||||
* Use `Class.forName()` for detection of native action bar. This provides
|
||||
compatability all the way back to Android 1.5.
|
||||
|
||||
|
||||
Version 2.0.0 *(2011-03-09)*
|
||||
----------------------------
|
||||
Complete rewrite!
|
||||
|
||||
* New and better API.
|
||||
* More sane logic and attachment to activity.
|
||||
* Extensible via generics. Implement any ActionBar or roll your own with
|
||||
minimal effort.
|
||||
* Now a library project for easy inclusion in applications.
|
||||
|
||||
|
||||
Version 1.0.0 *(2011-03-07)*
|
||||
----------------------------
|
||||
Initial release.
|
|
@ -1,11 +0,0 @@
|
|||
Contributing
|
||||
============
|
||||
|
||||
If you would like to contribute code to ActionBarSherlock you can do so through
|
||||
GitHub by forking the repository and sending a pull request.
|
||||
|
||||
When submitting code, please make every effort to follow existing conventions
|
||||
and style in order to keep the code as readable as possible. Please also make
|
||||
sure your code compiles by running `mvn clean verify`. Checkstyle failures
|
||||
during compilation indicate errors in your style and can be viewed in the
|
||||
`checkstyle-result.xml` file.
|
|
@ -1,202 +0,0 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
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.
|
|
@ -1,60 +0,0 @@
|
|||
ActionBarSherlock
|
||||
=================
|
||||
|
||||
ActionBarSherlock is an standalone library designed to facilitate the use of
|
||||
the action bar design pattern across all versions of Android through a single
|
||||
API.
|
||||
|
||||
The library will automatically use the [native ActionBar][2] implementation on
|
||||
Android 4.0 or later. For previous versions which do not include ActionBar, a
|
||||
custom action bar implementation based on the sources of Ice Cream Sandwich
|
||||
will automatically be wrapped around the layout. This allows you to easily
|
||||
develop an application with an action bar for every version of Android from 2.x
|
||||
and up.
|
||||
|
||||
**See http://actionbarsherlock.com for more information.**
|
||||
|
||||
![Example Image][3]
|
||||
|
||||
Try out the sample applications on the Android Market: [Feature Demos][4],
|
||||
[Fragments][5], and [RoboGuice][6].
|
||||
|
||||
Continuous integration is provided by [Travis CI][7].
|
||||
|
||||
|
||||
|
||||
Developed By
|
||||
============
|
||||
|
||||
* Jake Wharton - <jakewharton@gmail.com>
|
||||
|
||||
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
Copyright 2012 Jake Wharton
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
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.
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[1]: http://android-developers.blogspot.com/2011/03/fragments-for-all.html
|
||||
[2]: http://developer.android.com/guide/topics/ui/actionbar.html
|
||||
[3]: http://actionbarsherlock.com/static/feature.png
|
||||
[4]: https://play.google.com/store/apps/details?id=com.actionbarsherlock.sample.demos
|
||||
[5]: https://play.google.com/store/apps/details?id=com.actionbarsherlock.sample.fragments
|
||||
[6]: https://play.google.com/store/apps/details?id=com.actionbarsherlock.sample.roboguice
|
||||
[7]: https://travis-ci.org/JakeWharton/ActionBarSherlock
|
|
@ -1,24 +0,0 @@
|
|||
ActionBarSherlock Release Process
|
||||
=================================
|
||||
|
||||
1. Make sure she builds!
|
||||
|
||||
mvn clean verify
|
||||
|
||||
2. Ensure the `CHANGELOG.md` file has up-to-date information and the current date.
|
||||
3. Pull in the latest translations in the i18n module.
|
||||
4. Change all of the sample `AndroidManifest.xml` files to the correct version and bump the
|
||||
version code arbitrarily.
|
||||
|
||||
find actionbarsherlock-samples -name AndroidManifest.xml -exec sed -i '' 's|versionCode="[0-9]*"|versionCode="431"|g' {} \;
|
||||
find actionbarsherlock-samples -name AndroidManifest.xml -exec sed -i '' 's|versionName="[0-9.]*"|versionName="4.3.1"|g' {} \;
|
||||
|
||||
5. Make the release!
|
||||
|
||||
mvn clean release:clean
|
||||
mvn release:prepare release:perform
|
||||
|
||||
6. Promote the Maven artifact on Sonatype's OSS Nexus install.
|
||||
7. Deploy the latest website.
|
||||
|
||||
./deploy_website.sh
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="100" android:versionName="4.2.0" package="com.actionbarsherlock">
|
||||
|
||||
<uses-sdk android:minSdkVersion="7" android:targetSdkVersion="19"/>
|
||||
|
||||
</manifest>
|
|
@ -1,15 +0,0 @@
|
|||
ActionBarSherlock Library
|
||||
=========================
|
||||
|
||||
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
|
||||
[usage page][1].
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
[1]: http://actionbarsherlock.com/usage.html
|
|
@ -1,92 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project name="actionbarsherlock" default="help">
|
||||
|
||||
<!-- The local.properties file is created and updated by the 'android' tool.
|
||||
It contains the path to the SDK. It should *NOT* be checked into
|
||||
Version Control Systems. -->
|
||||
<property file="local.properties" />
|
||||
|
||||
<!-- The ant.properties file can be created by you. It is only edited by the
|
||||
'android' tool to add properties to it.
|
||||
This is the place to change some Ant specific build properties.
|
||||
Here are some properties you may want to change/update:
|
||||
|
||||
source.dir
|
||||
The name of the source directory. Default is 'src'.
|
||||
out.dir
|
||||
The name of the output directory. Default is 'bin'.
|
||||
|
||||
For other overridable properties, look at the beginning of the rules
|
||||
files in the SDK, at tools/ant/build.xml
|
||||
|
||||
Properties related to the SDK location or the project target should
|
||||
be updated using the 'android' tool with the 'update' action.
|
||||
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems.
|
||||
|
||||
-->
|
||||
<property file="ant.properties" />
|
||||
|
||||
<!-- if sdk.dir was not set from one of the property file, then
|
||||
get it from the ANDROID_HOME env var.
|
||||
This must be done before we load project.properties since
|
||||
the proguard config can use sdk.dir -->
|
||||
<property environment="env" />
|
||||
<condition property="sdk.dir" value="${env.ANDROID_HOME}">
|
||||
<isset property="env.ANDROID_HOME" />
|
||||
</condition>
|
||||
|
||||
<!-- The project.properties file is created and updated by the 'android'
|
||||
tool, as well as ADT.
|
||||
|
||||
This contains project specific properties such as project target, and library
|
||||
dependencies. Lower level build properties are stored in ant.properties
|
||||
(or in .classpath for Eclipse projects).
|
||||
|
||||
This file is an integral part of the build system for your
|
||||
application and should be checked into Version Control Systems. -->
|
||||
<loadproperties srcFile="project.properties" />
|
||||
|
||||
<!-- quick check on sdk.dir -->
|
||||
<fail
|
||||
message="sdk.dir is missing. Make sure to generate local.properties using 'android update project' or to inject it through the ANDROID_HOME environment variable."
|
||||
unless="sdk.dir"
|
||||
/>
|
||||
|
||||
<!--
|
||||
Import per project custom build rules if present at the root of the project.
|
||||
This is the place to put custom intermediary targets such as:
|
||||
-pre-build
|
||||
-pre-compile
|
||||
-post-compile (This is typically used for code obfuscation.
|
||||
Compiled code location: ${out.classes.absolute.dir}
|
||||
If this is not done in place, override ${out.dex.input.absolute.dir})
|
||||
-post-package
|
||||
-post-build
|
||||
-pre-clean
|
||||
-->
|
||||
<import file="custom_rules.xml" optional="true" />
|
||||
|
||||
<!-- Import the actual build file.
|
||||
|
||||
To customize existing targets, there are two options:
|
||||
- Customize only one target:
|
||||
- copy/paste the target into this file, *before* the
|
||||
<import> task.
|
||||
- customize it to your needs.
|
||||
- Customize the whole content of build.xml
|
||||
- copy/paste the content of the rules files (minus the top node)
|
||||
into this file, replacing the <import> task.
|
||||
- customize to your needs.
|
||||
|
||||
***********************
|
||||
****** IMPORTANT ******
|
||||
***********************
|
||||
In all cases you must update the value of version-tag below to read 'custom' instead of an integer,
|
||||
in order to avoid having your file be overridden by tools such as "android update project"
|
||||
-->
|
||||
<!-- version-tag: 1 -->
|
||||
<import file="${sdk.dir}/tools/ant/build.xml" />
|
||||
|
||||
</project>
|
Binary file not shown.
|
@ -1,24 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<lint>
|
||||
<issue id="ObsoleteLayoutParam" severity="ignore"/>
|
||||
<issue id="UnusedResources" severity="ignore"/>
|
||||
<issue id="NewApi" severity="ignore"/>
|
||||
<issue id="IconDuplicates" severity="ignore"/>
|
||||
<issue id="IconDuplicatesConfig" severity="ignore"/>
|
||||
<issue id="IconDensities" severity="ignore"/>
|
||||
<issue id="ContentDescription" severity="ignore"/>
|
||||
<issue id="SelectableText" severity="ignore"/>
|
||||
<issue id="NestedWeights" severity="ignore"/>
|
||||
<issue id="InefficientWeight" severity="ignore"/>
|
||||
<issue id="UselessParent" severity="ignore"/>
|
||||
<issue id="TypographyEllipsis" severity="ignore"/>
|
||||
<issue id="InlinedApi" severity="ignore"/>
|
||||
<issue id="DefaultLocale" severity="ignore"/>
|
||||
<issue id="WrongCall" severity="ignore"/>
|
||||
<issue id="DuplicateIds" severity="ignore"/>
|
||||
<issue id="MissingPrefix" severity="ignore"/>
|
||||
<issue id="UseCompoundDrawables" severity="ignore"/>
|
||||
<issue id="Overdraw" severity="ignore"/>
|
||||
<issue id="Registered" severity="ignore"/>
|
||||
<issue id="ViewConstructor" severity="ignore"/>
|
||||
</lint>
|
|
@ -1,137 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<parent>
|
||||
<groupId>com.actionbarsherlock</groupId>
|
||||
<artifactId>parent</artifactId>
|
||||
<version>4.3.1</version>
|
||||
<relativePath>../pom.xml</relativePath>
|
||||
</parent>
|
||||
|
||||
<artifactId>actionbarsherlock</artifactId>
|
||||
<name>ActionBarSherlock</name>
|
||||
<packaging>apklib</packaging>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.google.android</groupId>
|
||||
<artifactId>android</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.google.android</groupId>
|
||||
<artifactId>support-v4</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>junit</groupId>
|
||||
<artifactId>junit</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.easytesting</groupId>
|
||||
<artifactId>fest-assert-core</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.robolectric</groupId>
|
||||
<artifactId>robolectric</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<sourceDirectory>src</sourceDirectory>
|
||||
<testSourceDirectory>test</testSourceDirectory>
|
||||
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>com.jayway.maven.plugins.android.generation2</groupId>
|
||||
<artifactId>android-maven-plugin</artifactId>
|
||||
<extensions>true</extensions>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.apache.maven.plugins</groupId>
|
||||
<artifactId>maven-javadoc-plugin</artifactId>
|
||||
<configuration>
|
||||
<skip>true</skip>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>com.google.code.maven-replacer-plugin</groupId>
|
||||
<artifactId>maven-replacer-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>process-sources</phase>
|
||||
<goals>
|
||||
<goal>replace</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<ignoreMissingFile>false</ignoreMissingFile>
|
||||
<file>target/generated-sources/r/com/actionbarsherlock/R.java</file>
|
||||
<outputFile>target/generated-sources/r/com/actionbarsherlock/R.java</outputFile>
|
||||
<regex>false</regex>
|
||||
<token>static final int</token>
|
||||
<value>static int</value>
|
||||
</configuration>
|
||||
</plugin>
|
||||
|
||||
<plugin>
|
||||
<groupId>org.codehaus.mojo</groupId>
|
||||
<artifactId>build-helper-maven-plugin</artifactId>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>attach-artifact</goal>
|
||||
</goals>
|
||||
<configuration>
|
||||
<artifacts>
|
||||
<artifact>
|
||||
<type>jar</type>
|
||||
<file>${project.build.directory}/${project.build.finalName}.jar</file>
|
||||
</artifact>
|
||||
</artifacts>
|
||||
</configuration>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
|
||||
<pluginManagement>
|
||||
<plugins>
|
||||
<!--This plugin's configuration is used to store Eclipse m2e settings only. It has no influence on the Maven build itself.-->
|
||||
<plugin>
|
||||
<groupId>org.eclipse.m2e</groupId>
|
||||
<artifactId>lifecycle-mapping</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<configuration>
|
||||
<lifecycleMappingMetadata>
|
||||
<pluginExecutions>
|
||||
<pluginExecution>
|
||||
<pluginExecutionFilter>
|
||||
<groupId>com.google.code.maven-replacer-plugin</groupId>
|
||||
<artifactId>maven-replacer-plugin</artifactId>
|
||||
<versionRange>[1.4.0,)</versionRange>
|
||||
<goals>
|
||||
<goal>replace</goal>
|
||||
</goals>
|
||||
</pluginExecutionFilter>
|
||||
<action>
|
||||
<ignore />
|
||||
</action>
|
||||
</pluginExecution>
|
||||
</pluginExecutions>
|
||||
</lifecycleMappingMetadata>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</pluginManagement>
|
||||
</build>
|
||||
</project>
|
|
@ -1,143 +0,0 @@
|
|||
package android.support.v4.app;
|
||||
|
||||
import android.util.Log;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnCreatePanelMenuListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnMenuItemSelectedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnPreparePanelListener;
|
||||
import com.actionbarsherlock.BuildConfig;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/** I'm in ur package. Stealing ur variables. */
|
||||
public abstract class Watson extends FragmentActivity implements OnCreatePanelMenuListener, OnPreparePanelListener, OnMenuItemSelectedListener {
|
||||
private static final String TAG = "Watson";
|
||||
|
||||
/** Fragment interface for menu creation callback. */
|
||||
public interface OnCreateOptionsMenuListener {
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater);
|
||||
}
|
||||
/** Fragment interface for menu preparation callback. */
|
||||
public interface OnPrepareOptionsMenuListener {
|
||||
public void onPrepareOptionsMenu(Menu menu);
|
||||
}
|
||||
/** Fragment interface for menu item selection callback. */
|
||||
public interface OnOptionsItemSelectedListener {
|
||||
public boolean onOptionsItemSelected(MenuItem item);
|
||||
}
|
||||
|
||||
private ArrayList<Fragment> mCreatedMenus;
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Sherlock menu handling
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public boolean onCreatePanelMenu(int featureId, Menu menu) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[onCreatePanelMenu] featureId: " + featureId + ", menu: " + menu);
|
||||
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
boolean result = onCreateOptionsMenu(menu);
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[onCreatePanelMenu] activity create result: " + result);
|
||||
|
||||
MenuInflater inflater = getSupportMenuInflater();
|
||||
boolean show = false;
|
||||
ArrayList<Fragment> newMenus = null;
|
||||
if (mFragments.mAdded != null) {
|
||||
for (int i = 0; i < mFragments.mAdded.size(); i++) {
|
||||
Fragment f = mFragments.mAdded.get(i);
|
||||
if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible && f instanceof OnCreateOptionsMenuListener) {
|
||||
show = true;
|
||||
((OnCreateOptionsMenuListener)f).onCreateOptionsMenu(menu, inflater);
|
||||
if (newMenus == null) {
|
||||
newMenus = new ArrayList<Fragment>();
|
||||
}
|
||||
newMenus.add(f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mCreatedMenus != null) {
|
||||
for (int i = 0; i < mCreatedMenus.size(); i++) {
|
||||
Fragment f = mCreatedMenus.get(i);
|
||||
if (newMenus == null || !newMenus.contains(f)) {
|
||||
f.onDestroyOptionsMenu();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mCreatedMenus = newMenus;
|
||||
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[onCreatePanelMenu] fragments create result: " + show);
|
||||
result |= show;
|
||||
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[onCreatePanelMenu] returning " + result);
|
||||
return result;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreparePanel(int featureId, View view, Menu menu) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[onPreparePanel] featureId: " + featureId + ", view: " + view + " menu: " + menu);
|
||||
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
boolean result = onPrepareOptionsMenu(menu);
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[onPreparePanel] activity prepare result: " + result);
|
||||
|
||||
boolean show = false;
|
||||
if (mFragments.mAdded != null) {
|
||||
for (int i = 0; i < mFragments.mAdded.size(); i++) {
|
||||
Fragment f = mFragments.mAdded.get(i);
|
||||
if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible && f instanceof OnPrepareOptionsMenuListener) {
|
||||
show = true;
|
||||
((OnPrepareOptionsMenuListener)f).onPrepareOptionsMenu(menu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[onPreparePanel] fragments prepare result: " + show);
|
||||
result |= show;
|
||||
|
||||
result &= menu.hasVisibleItems();
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[onPreparePanel] returning " + result);
|
||||
return result;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[onMenuItemSelected] featureId: " + featureId + ", item: " + item);
|
||||
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
if (onOptionsItemSelected(item)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mFragments.mAdded != null) {
|
||||
for (int i = 0; i < mFragments.mAdded.size(); i++) {
|
||||
Fragment f = mFragments.mAdded.get(i);
|
||||
if (f != null && !f.mHidden && f.mHasMenu && f.mMenuVisible && f instanceof OnOptionsItemSelectedListener) {
|
||||
if (((OnOptionsItemSelectedListener)f).onOptionsItemSelected(item)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public abstract boolean onCreateOptionsMenu(Menu menu);
|
||||
|
||||
public abstract boolean onPrepareOptionsMenu(Menu menu);
|
||||
|
||||
public abstract boolean onOptionsItemSelected(MenuItem item);
|
||||
|
||||
public abstract MenuInflater getSupportMenuInflater();
|
||||
}
|
|
@ -1,799 +0,0 @@
|
|||
package com.actionbarsherlock;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.Window;
|
||||
import com.actionbarsherlock.app.ActionBar;
|
||||
import com.actionbarsherlock.internal.ActionBarSherlockCompat;
|
||||
import com.actionbarsherlock.internal.ActionBarSherlockNative;
|
||||
import com.actionbarsherlock.view.ActionMode;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.util.HashMap;
|
||||
import java.util.Iterator;
|
||||
|
||||
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
|
||||
/**
|
||||
* <p>Helper for implementing the action bar design pattern across all versions
|
||||
* of Android.</p>
|
||||
*
|
||||
* <p>This class will manage interaction with a custom action bar based on the
|
||||
* Android 4.0 source code. The exposed API mirrors that of its native
|
||||
* counterpart and you should refer to its documentation for instruction.</p>
|
||||
*
|
||||
* @author Jake Wharton <jakewharton@gmail.com>
|
||||
*/
|
||||
public abstract class ActionBarSherlock {
|
||||
protected static final String TAG = "ActionBarSherlock";
|
||||
|
||||
private static final Class<?>[] CONSTRUCTOR_ARGS = new Class[] { Activity.class, int.class };
|
||||
private static final HashMap<Implementation, Class<? extends ActionBarSherlock>> IMPLEMENTATIONS =
|
||||
new HashMap<Implementation, Class<? extends ActionBarSherlock>>();
|
||||
|
||||
static {
|
||||
//Register our two built-in implementations
|
||||
registerImplementation(ActionBarSherlockCompat.class);
|
||||
registerImplementation(ActionBarSherlockNative.class);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* <p>Denotes an implementation of ActionBarSherlock which provides an
|
||||
* action bar-enhanced experience.</p>
|
||||
*/
|
||||
@Target(ElementType.TYPE)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
public @interface Implementation {
|
||||
static final int DEFAULT_API = -1;
|
||||
static final int DEFAULT_DPI = -1;
|
||||
|
||||
int api() default DEFAULT_API;
|
||||
int dpi() default DEFAULT_DPI;
|
||||
}
|
||||
|
||||
|
||||
/** Activity interface for menu creation callback. */
|
||||
public interface OnCreatePanelMenuListener {
|
||||
public boolean onCreatePanelMenu(int featureId, Menu menu);
|
||||
}
|
||||
/** Activity interface for menu creation callback. */
|
||||
public interface OnCreateOptionsMenuListener {
|
||||
public boolean onCreateOptionsMenu(Menu menu);
|
||||
}
|
||||
/** Activity interface for menu item selection callback. */
|
||||
public interface OnMenuItemSelectedListener {
|
||||
public boolean onMenuItemSelected(int featureId, MenuItem item);
|
||||
}
|
||||
/** Activity interface for menu item selection callback. */
|
||||
public interface OnOptionsItemSelectedListener {
|
||||
public boolean onOptionsItemSelected(MenuItem item);
|
||||
}
|
||||
/** Activity interface for menu preparation callback. */
|
||||
public interface OnPreparePanelListener {
|
||||
public boolean onPreparePanel(int featureId, View view, Menu menu);
|
||||
}
|
||||
/** Activity interface for menu preparation callback. */
|
||||
public interface OnPrepareOptionsMenuListener {
|
||||
public boolean onPrepareOptionsMenu(Menu menu);
|
||||
}
|
||||
/** Activity interface for action mode finished callback. */
|
||||
public interface OnActionModeFinishedListener {
|
||||
public void onActionModeFinished(ActionMode mode);
|
||||
}
|
||||
/** Activity interface for action mode started callback. */
|
||||
public interface OnActionModeStartedListener {
|
||||
public void onActionModeStarted(ActionMode mode);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* If set, the logic in these classes will assume that an {@link Activity}
|
||||
* is dispatching all of the required events to the class. This flag should
|
||||
* only be used internally or if you are creating your own base activity
|
||||
* modeled after one of the included types (e.g., {@code SherlockActivity}).
|
||||
*/
|
||||
public static final int FLAG_DELEGATE = 1;
|
||||
|
||||
|
||||
/**
|
||||
* Register an ActionBarSherlock implementation.
|
||||
*
|
||||
* @param implementationClass Target implementation class which extends
|
||||
* {@link ActionBarSherlock}. This class must also be annotated with
|
||||
* {@link Implementation}.
|
||||
*/
|
||||
public static void registerImplementation(Class<? extends ActionBarSherlock> implementationClass) {
|
||||
if (!implementationClass.isAnnotationPresent(Implementation.class)) {
|
||||
throw new IllegalArgumentException("Class " + implementationClass.getSimpleName() + " is not annotated with @Implementation");
|
||||
} else if (IMPLEMENTATIONS.containsValue(implementationClass)) {
|
||||
if (BuildConfig.DEBUG) Log.w(TAG, "Class " + implementationClass.getSimpleName() + " already registered");
|
||||
return;
|
||||
}
|
||||
|
||||
Implementation impl = implementationClass.getAnnotation(Implementation.class);
|
||||
if (BuildConfig.DEBUG) Log.i(TAG, "Registering " + implementationClass.getSimpleName() + " with qualifier " + impl);
|
||||
IMPLEMENTATIONS.put(impl, implementationClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Unregister an ActionBarSherlock implementation. <strong>This should be
|
||||
* considered very volatile and you should only use it if you know what
|
||||
* you are doing.</strong> You have been warned.
|
||||
*
|
||||
* @param implementationClass Target implementation class.
|
||||
* @return Boolean indicating whether the class was removed.
|
||||
*/
|
||||
public static boolean unregisterImplementation(Class<? extends ActionBarSherlock> implementationClass) {
|
||||
return IMPLEMENTATIONS.values().remove(implementationClass);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap an activity with an action bar abstraction which will enable the
|
||||
* use of a custom implementation on platforms where a native version does
|
||||
* not exist.
|
||||
*
|
||||
* @param activity Activity to wrap.
|
||||
* @return Instance to interact with the action bar.
|
||||
*/
|
||||
public static ActionBarSherlock wrap(Activity activity) {
|
||||
return wrap(activity, 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap an activity with an action bar abstraction which will enable the
|
||||
* use of a custom implementation on platforms where a native version does
|
||||
* not exist.
|
||||
*
|
||||
* @param activity Owning activity.
|
||||
* @param flags Option flags to control behavior.
|
||||
* @return Instance to interact with the action bar.
|
||||
*/
|
||||
public static ActionBarSherlock wrap(Activity activity, int flags) {
|
||||
//Create a local implementation map we can modify
|
||||
HashMap<Implementation, Class<? extends ActionBarSherlock>> impls =
|
||||
new HashMap<Implementation, Class<? extends ActionBarSherlock>>(IMPLEMENTATIONS);
|
||||
boolean hasQualfier;
|
||||
|
||||
/* DPI FILTERING */
|
||||
hasQualfier = false;
|
||||
for (Implementation key : impls.keySet()) {
|
||||
//Only honor TVDPI as a specific qualifier
|
||||
if (key.dpi() == DisplayMetrics.DENSITY_TV) {
|
||||
hasQualfier = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasQualfier) {
|
||||
final boolean isTvDpi = activity.getResources().getDisplayMetrics().densityDpi == DisplayMetrics.DENSITY_TV;
|
||||
for (Iterator<Implementation> keys = impls.keySet().iterator(); keys.hasNext(); ) {
|
||||
int keyDpi = keys.next().dpi();
|
||||
if ((isTvDpi && keyDpi != DisplayMetrics.DENSITY_TV)
|
||||
|| (!isTvDpi && keyDpi == DisplayMetrics.DENSITY_TV)) {
|
||||
keys.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* API FILTERING */
|
||||
hasQualfier = false;
|
||||
for (Implementation key : impls.keySet()) {
|
||||
if (key.api() != Implementation.DEFAULT_API) {
|
||||
hasQualfier = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasQualfier) {
|
||||
final int runtimeApi = Build.VERSION.SDK_INT;
|
||||
int bestApi = 0;
|
||||
for (Iterator<Implementation> keys = impls.keySet().iterator(); keys.hasNext(); ) {
|
||||
int keyApi = keys.next().api();
|
||||
if (keyApi > runtimeApi) {
|
||||
keys.remove();
|
||||
} else if (keyApi > bestApi) {
|
||||
bestApi = keyApi;
|
||||
}
|
||||
}
|
||||
for (Iterator<Implementation> keys = impls.keySet().iterator(); keys.hasNext(); ) {
|
||||
if (keys.next().api() != bestApi) {
|
||||
keys.remove();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (impls.size() > 1) {
|
||||
throw new IllegalStateException("More than one implementation matches configuration.");
|
||||
}
|
||||
if (impls.isEmpty()) {
|
||||
throw new IllegalStateException("No implementations match configuration.");
|
||||
}
|
||||
Class<? extends ActionBarSherlock> impl = impls.values().iterator().next();
|
||||
if (BuildConfig.DEBUG) Log.i(TAG, "Using implementation: " + impl.getSimpleName());
|
||||
|
||||
try {
|
||||
Constructor<? extends ActionBarSherlock> ctor = impl.getConstructor(CONSTRUCTOR_ARGS);
|
||||
return ctor.newInstance(activity, flags);
|
||||
} catch (NoSuchMethodException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IllegalArgumentException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InstantiationException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (IllegalAccessException e) {
|
||||
throw new RuntimeException(e);
|
||||
} catch (InvocationTargetException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/** Activity which is displaying the action bar. Also used for context. */
|
||||
protected final Activity mActivity;
|
||||
/** Whether delegating actions for the activity or managing ourselves. */
|
||||
protected final boolean mIsDelegate;
|
||||
|
||||
/** Reference to our custom menu inflater which supports action items. */
|
||||
protected MenuInflater mMenuInflater;
|
||||
|
||||
|
||||
|
||||
protected ActionBarSherlock(Activity activity, int flags) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[<ctor>] activity: " + activity + ", flags: " + flags);
|
||||
|
||||
mActivity = activity;
|
||||
mIsDelegate = (flags & FLAG_DELEGATE) != 0;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get the current action bar instance.
|
||||
*
|
||||
* @return Action bar instance.
|
||||
*/
|
||||
public abstract ActionBar getActionBar();
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Lifecycle and interaction callbacks when delegating
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Notify action bar of a configuration change event. Should be dispatched
|
||||
* after the call to the superclass implementation.
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* @Override
|
||||
* public void onConfigurationChanged(Configuration newConfig) {
|
||||
* super.onConfigurationChanged(newConfig);
|
||||
* mSherlock.dispatchConfigurationChanged(newConfig);
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @param newConfig The new device configuration.
|
||||
*/
|
||||
public void dispatchConfigurationChanged(Configuration newConfig) {}
|
||||
|
||||
/**
|
||||
* Notify the action bar that the activity has finished its resuming. This
|
||||
* should be dispatched after the call to the superclass implementation.
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* @Override
|
||||
* protected void onPostResume() {
|
||||
* super.onPostResume();
|
||||
* mSherlock.dispatchPostResume();
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
*/
|
||||
public void dispatchPostResume() {}
|
||||
|
||||
/**
|
||||
* Notify the action bar that the activity is pausing. This should be
|
||||
* dispatched before the call to the superclass implementation.
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* @Override
|
||||
* protected void onPause() {
|
||||
* mSherlock.dispatchPause();
|
||||
* super.onPause();
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
*/
|
||||
public void dispatchPause() {}
|
||||
|
||||
/**
|
||||
* Notify the action bar that the activity is stopping. This should be
|
||||
* called before the superclass implementation.
|
||||
*
|
||||
* <blockquote><p>
|
||||
* @Override
|
||||
* protected void onStop() {
|
||||
* mSherlock.dispatchStop();
|
||||
* super.onStop();
|
||||
* }
|
||||
* </p></blockquote>
|
||||
*/
|
||||
public void dispatchStop() {}
|
||||
|
||||
/**
|
||||
* Indicate that the menu should be recreated by calling
|
||||
* {@link OnCreateOptionsMenuListener#onCreateOptionsMenu(com.actionbarsherlock.view.Menu)}.
|
||||
*/
|
||||
public abstract void dispatchInvalidateOptionsMenu();
|
||||
|
||||
/**
|
||||
* Notify the action bar that it should display its overflow menu if it is
|
||||
* appropriate for the device. The implementation should conditionally
|
||||
* call the superclass method only if this method returns {@code false}.
|
||||
*
|
||||
* <blockquote><p>
|
||||
* @Override
|
||||
* public void openOptionsMenu() {
|
||||
* if (!mSherlock.dispatchOpenOptionsMenu()) {
|
||||
* super.openOptionsMenu();
|
||||
* }
|
||||
* }
|
||||
* </p></blockquote>
|
||||
*
|
||||
* @return {@code true} if the opening of the menu was handled internally.
|
||||
*/
|
||||
public boolean dispatchOpenOptionsMenu() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the action bar that it should close its overflow menu if it is
|
||||
* appropriate for the device. This implementation should conditionally
|
||||
* call the superclass method only if this method returns {@code false}.
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* @Override
|
||||
* public void closeOptionsMenu() {
|
||||
* if (!mSherlock.dispatchCloseOptionsMenu()) {
|
||||
* super.closeOptionsMenu();
|
||||
* }
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @return {@code true} if the closing of the menu was handled internally.
|
||||
*/
|
||||
public boolean dispatchCloseOptionsMenu() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the class that the activity has finished its creation. This
|
||||
* should be called after the superclass implementation.
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* @Override
|
||||
* protected void onPostCreate(Bundle savedInstanceState) {
|
||||
* mSherlock.dispatchPostCreate(savedInstanceState);
|
||||
* super.onPostCreate(savedInstanceState);
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @param savedInstanceState If the activity is being re-initialized after
|
||||
* previously being shut down then this Bundle
|
||||
* contains the data it most recently supplied in
|
||||
* {@link Activity#}onSaveInstanceState(Bundle)}.
|
||||
* <strong>Note: Otherwise it is null.</strong>
|
||||
*/
|
||||
public void dispatchPostCreate(Bundle savedInstanceState) {}
|
||||
|
||||
/**
|
||||
* Notify the action bar that the title has changed and the action bar
|
||||
* should be updated to reflect the change. This should be called before
|
||||
* the superclass implementation.
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* @Override
|
||||
* protected void onTitleChanged(CharSequence title, int color) {
|
||||
* mSherlock.dispatchTitleChanged(title, color);
|
||||
* super.onTitleChanged(title, color);
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @param title New activity title.
|
||||
* @param color New activity color.
|
||||
*/
|
||||
public void dispatchTitleChanged(CharSequence title, int color) {}
|
||||
|
||||
/**
|
||||
* Notify the action bar the user has created a key event. This is used to
|
||||
* toggle the display of the overflow action item with the menu key and to
|
||||
* close the action mode or expanded action item with the back key.
|
||||
*
|
||||
* <blockquote><pre>
|
||||
* @Override
|
||||
* public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
* if (mSherlock.dispatchKeyEvent(event)) {
|
||||
* return true;
|
||||
* }
|
||||
* return super.dispatchKeyEvent(event);
|
||||
* }
|
||||
* </pre></blockquote>
|
||||
*
|
||||
* @param event Description of the key event.
|
||||
* @return {@code true} if the event was handled.
|
||||
*/
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the action bar that the Activity has triggered a menu creation
|
||||
* which should happen on the conclusion of {@link Activity#onCreate}. This
|
||||
* will be used to gain a reference to the native menu for native and
|
||||
* overflow binding as well as to indicate when compatibility create should
|
||||
* occur for the first time.
|
||||
*
|
||||
* @param menu Activity native menu.
|
||||
* @return {@code true} since we always want to say that we have a native
|
||||
*/
|
||||
public abstract boolean dispatchCreateOptionsMenu(android.view.Menu menu);
|
||||
|
||||
/**
|
||||
* Notify the action bar that the Activity has triggered a menu preparation
|
||||
* which usually means that the user has requested the overflow menu via a
|
||||
* hardware menu key. You should return the result of this method call and
|
||||
* not call the superclass implementation.
|
||||
*
|
||||
* <blockquote><p>
|
||||
* @Override
|
||||
* public final boolean onPrepareOptionsMenu(android.view.Menu menu) {
|
||||
* return mSherlock.dispatchPrepareOptionsMenu(menu);
|
||||
* }
|
||||
* </p></blockquote>
|
||||
*
|
||||
* @param menu Activity native menu.
|
||||
* @return {@code true} if menu display should proceed.
|
||||
*/
|
||||
public abstract boolean dispatchPrepareOptionsMenu(android.view.Menu menu);
|
||||
|
||||
/**
|
||||
* Notify the action bar that a native options menu item has been selected.
|
||||
* The implementation should return the result of this method call.
|
||||
*
|
||||
* <blockquote><p>
|
||||
* @Override
|
||||
* public final boolean onOptionsItemSelected(android.view.MenuItem item) {
|
||||
* return mSherlock.dispatchOptionsItemSelected(item);
|
||||
* }
|
||||
* </p></blockquote>
|
||||
*
|
||||
* @param item Options menu item.
|
||||
* @return @{code true} if the selection was handled.
|
||||
*/
|
||||
public abstract boolean dispatchOptionsItemSelected(android.view.MenuItem item);
|
||||
|
||||
/**
|
||||
* Notify the action bar that the overflow menu has been opened. The
|
||||
* implementation should conditionally return {@code true} if this method
|
||||
* returns {@code true}, otherwise return the result of the superclass
|
||||
* method.
|
||||
*
|
||||
* <blockquote><p>
|
||||
* @Override
|
||||
* public final boolean onMenuOpened(int featureId, android.view.Menu menu) {
|
||||
* if (mSherlock.dispatchMenuOpened(featureId, menu)) {
|
||||
* return true;
|
||||
* }
|
||||
* return super.onMenuOpened(featureId, menu);
|
||||
* }
|
||||
* </p></blockquote>
|
||||
*
|
||||
* @param featureId Window feature which triggered the event.
|
||||
* @param menu Activity native menu.
|
||||
* @return {@code true} if the event was handled by this method.
|
||||
*/
|
||||
public boolean dispatchMenuOpened(int featureId, android.view.Menu menu) {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the action bar that the overflow menu has been closed. This
|
||||
* method should be called before the superclass implementation.
|
||||
*
|
||||
* <blockquote><p>
|
||||
* @Override
|
||||
* public void onPanelClosed(int featureId, android.view.Menu menu) {
|
||||
* mSherlock.dispatchPanelClosed(featureId, menu);
|
||||
* super.onPanelClosed(featureId, menu);
|
||||
* }
|
||||
* </p></blockquote>
|
||||
*
|
||||
* @param featureId
|
||||
* @param menu
|
||||
*/
|
||||
public void dispatchPanelClosed(int featureId, android.view.Menu menu) {}
|
||||
|
||||
/**
|
||||
* Notify the action bar that the activity has been destroyed. This method
|
||||
* should be called before the superclass implementation.
|
||||
*
|
||||
* <blockquote><p>
|
||||
* @Override
|
||||
* public void onDestroy() {
|
||||
* mSherlock.dispatchDestroy();
|
||||
* super.onDestroy();
|
||||
* }
|
||||
* </p></blockquote>
|
||||
*/
|
||||
public void dispatchDestroy() {}
|
||||
|
||||
public void dispatchSaveInstanceState(Bundle outState) {}
|
||||
|
||||
public void dispatchRestoreInstanceState(Bundle savedInstanceState) {}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Internal method to trigger the menu creation process.
|
||||
*
|
||||
* @return {@code true} if menu creation should proceed.
|
||||
*/
|
||||
protected final boolean callbackCreateOptionsMenu(Menu menu) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[callbackCreateOptionsMenu] menu: " + menu);
|
||||
|
||||
boolean result = true;
|
||||
if (mActivity instanceof OnCreatePanelMenuListener) {
|
||||
OnCreatePanelMenuListener listener = (OnCreatePanelMenuListener)mActivity;
|
||||
result = listener.onCreatePanelMenu(Window.FEATURE_OPTIONS_PANEL, menu);
|
||||
} else if (mActivity instanceof OnCreateOptionsMenuListener) {
|
||||
OnCreateOptionsMenuListener listener = (OnCreateOptionsMenuListener)mActivity;
|
||||
result = listener.onCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[callbackCreateOptionsMenu] returning " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method to trigger the menu preparation process.
|
||||
*
|
||||
* @return {@code true} if menu preparation should proceed.
|
||||
*/
|
||||
protected final boolean callbackPrepareOptionsMenu(Menu menu) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[callbackPrepareOptionsMenu] menu: " + menu);
|
||||
|
||||
boolean result = true;
|
||||
if (mActivity instanceof OnPreparePanelListener) {
|
||||
OnPreparePanelListener listener = (OnPreparePanelListener)mActivity;
|
||||
result = listener.onPreparePanel(Window.FEATURE_OPTIONS_PANEL, null, menu);
|
||||
} else if (mActivity instanceof OnPrepareOptionsMenuListener) {
|
||||
OnPrepareOptionsMenuListener listener = (OnPrepareOptionsMenuListener)mActivity;
|
||||
result = listener.onPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[callbackPrepareOptionsMenu] returning " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal method for dispatching options menu selection to the owning
|
||||
* activity callback.
|
||||
*
|
||||
* @param item Selected options menu item.
|
||||
* @return {@code true} if the item selection was handled in the callback.
|
||||
*/
|
||||
protected final boolean callbackOptionsItemSelected(MenuItem item) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[callbackOptionsItemSelected] item: " + item.getTitleCondensed());
|
||||
|
||||
boolean result = false;
|
||||
if (mActivity instanceof OnMenuItemSelectedListener) {
|
||||
OnMenuItemSelectedListener listener = (OnMenuItemSelectedListener)mActivity;
|
||||
result = listener.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, item);
|
||||
} else if (mActivity instanceof OnOptionsItemSelectedListener) {
|
||||
OnOptionsItemSelectedListener listener = (OnOptionsItemSelectedListener)mActivity;
|
||||
result = listener.onOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[callbackOptionsItemSelected] returning " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
/**
|
||||
* Query for the availability of a certain feature.
|
||||
*
|
||||
* @param featureId The feature ID to check.
|
||||
* @return {@code true} if feature is enabled, {@code false} otherwise.
|
||||
*/
|
||||
public abstract boolean hasFeature(int featureId);
|
||||
|
||||
/**
|
||||
* Enable extended screen features. This must be called before
|
||||
* {@code setContentView()}. May be called as many times as desired as long
|
||||
* as it is before {@code setContentView()}. If not called, no extended
|
||||
* features will be available. You can not turn off a feature once it is
|
||||
* requested.
|
||||
*
|
||||
* @param featureId The desired features, defined as constants by Window.
|
||||
* @return Returns true if the requested feature is supported and now
|
||||
* enabled.
|
||||
*/
|
||||
public abstract boolean requestFeature(int featureId);
|
||||
|
||||
/**
|
||||
* Set extra options that will influence the UI for this window.
|
||||
*
|
||||
* @param uiOptions Flags specifying extra options for this window.
|
||||
*/
|
||||
public abstract void setUiOptions(int uiOptions);
|
||||
|
||||
/**
|
||||
* Set extra options that will influence the UI for this window. Only the
|
||||
* bits filtered by mask will be modified.
|
||||
*
|
||||
* @param uiOptions Flags specifying extra options for this window.
|
||||
* @param mask Flags specifying which options should be modified. Others
|
||||
* will remain unchanged.
|
||||
*/
|
||||
public abstract void setUiOptions(int uiOptions, int mask);
|
||||
|
||||
/**
|
||||
* Set the content of the activity inside the action bar.
|
||||
*
|
||||
* @param layoutResId Layout resource ID.
|
||||
*/
|
||||
public abstract void setContentView(int layoutResId);
|
||||
|
||||
/**
|
||||
* Set the content of the activity inside the action bar.
|
||||
*
|
||||
* @param view The desired content to display.
|
||||
*/
|
||||
public void setContentView(View view) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[setContentView] view: " + view);
|
||||
|
||||
setContentView(view, new ViewGroup.LayoutParams(MATCH_PARENT, MATCH_PARENT));
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the content of the activity inside the action bar.
|
||||
*
|
||||
* @param view The desired content to display.
|
||||
* @param params Layout parameters to apply to the view.
|
||||
*/
|
||||
public abstract void setContentView(View view, ViewGroup.LayoutParams params);
|
||||
|
||||
/**
|
||||
* Variation on {@link #setContentView(android.view.View, android.view.ViewGroup.LayoutParams)}
|
||||
* to add an additional content view to the screen. Added after any
|
||||
* existing ones on the screen -- existing views are NOT removed.
|
||||
*
|
||||
* @param view The desired content to display.
|
||||
* @param params Layout parameters for the view.
|
||||
*/
|
||||
public abstract void addContentView(View view, ViewGroup.LayoutParams params);
|
||||
|
||||
/**
|
||||
* Change the title associated with this activity.
|
||||
*/
|
||||
public abstract void setTitle(CharSequence title);
|
||||
|
||||
/**
|
||||
* Change the title associated with this activity.
|
||||
*/
|
||||
public void setTitle(int resId) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[setTitle] resId: " + resId);
|
||||
|
||||
setTitle(mActivity.getString(resId));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the visibility of the progress bar in the title.
|
||||
* <p>
|
||||
* In order for the progress bar to be shown, the feature must be requested
|
||||
* via {@link #requestWindowFeature(int)}.
|
||||
*
|
||||
* @param visible Whether to show the progress bars in the title.
|
||||
*/
|
||||
public abstract void setProgressBarVisibility(boolean visible);
|
||||
|
||||
/**
|
||||
* Sets the visibility of the indeterminate progress bar in the title.
|
||||
* <p>
|
||||
* In order for the progress bar to be shown, the feature must be requested
|
||||
* via {@link #requestWindowFeature(int)}.
|
||||
*
|
||||
* @param visible Whether to show the progress bars in the title.
|
||||
*/
|
||||
public abstract void setProgressBarIndeterminateVisibility(boolean visible);
|
||||
|
||||
/**
|
||||
* Sets whether the horizontal progress bar in the title should be indeterminate (the circular
|
||||
* is always indeterminate).
|
||||
* <p>
|
||||
* In order for the progress bar to be shown, the feature must be requested
|
||||
* via {@link #requestWindowFeature(int)}.
|
||||
*
|
||||
* @param indeterminate Whether the horizontal progress bar should be indeterminate.
|
||||
*/
|
||||
public abstract void setProgressBarIndeterminate(boolean indeterminate);
|
||||
|
||||
/**
|
||||
* Sets the progress for the progress bars in the title.
|
||||
* <p>
|
||||
* In order for the progress bar to be shown, the feature must be requested
|
||||
* via {@link #requestWindowFeature(int)}.
|
||||
*
|
||||
* @param progress The progress for the progress bar. Valid ranges are from
|
||||
* 0 to 10000 (both inclusive). If 10000 is given, the progress
|
||||
* bar will be completely filled and will fade out.
|
||||
*/
|
||||
public abstract void setProgress(int progress);
|
||||
|
||||
/**
|
||||
* Sets the secondary progress for the progress bar in the title. This
|
||||
* progress is drawn between the primary progress (set via
|
||||
* {@link #setProgress(int)} and the background. It can be ideal for media
|
||||
* scenarios such as showing the buffering progress while the default
|
||||
* progress shows the play progress.
|
||||
* <p>
|
||||
* In order for the progress bar to be shown, the feature must be requested
|
||||
* via {@link #requestWindowFeature(int)}.
|
||||
*
|
||||
* @param secondaryProgress The secondary progress for the progress bar. Valid ranges are from
|
||||
* 0 to 10000 (both inclusive).
|
||||
*/
|
||||
public abstract void setSecondaryProgress(int secondaryProgress);
|
||||
|
||||
/**
|
||||
* Get a menu inflater instance which supports the newer menu attributes.
|
||||
*
|
||||
* @return Menu inflater instance.
|
||||
*/
|
||||
public MenuInflater getMenuInflater() {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[getMenuInflater]");
|
||||
|
||||
// Make sure that action views can get an appropriate theme.
|
||||
if (mMenuInflater == null) {
|
||||
if (getActionBar() != null) {
|
||||
mMenuInflater = new MenuInflater(getThemedContext(), mActivity);
|
||||
} else {
|
||||
mMenuInflater = new MenuInflater(mActivity);
|
||||
}
|
||||
}
|
||||
return mMenuInflater;
|
||||
}
|
||||
|
||||
protected abstract Context getThemedContext();
|
||||
|
||||
/**
|
||||
* Start an action mode.
|
||||
*
|
||||
* @param callback Callback that will manage lifecycle events for this
|
||||
* context mode.
|
||||
* @return The ContextMode that was started, or null if it was canceled.
|
||||
* @see ActionMode
|
||||
*/
|
||||
public abstract ActionMode startActionMode(ActionMode.Callback callback);
|
||||
|
||||
/**
|
||||
* Ensure that the action bar is attached.
|
||||
*/
|
||||
public void ensureActionBar() {}
|
||||
}
|
|
@ -1,956 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.app;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewDebug;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewGroup.MarginLayoutParams;
|
||||
import android.widget.SpinnerAdapter;
|
||||
|
||||
/**
|
||||
* A window feature at the top of the activity that may display the activity title, navigation
|
||||
* modes, and other interactive items.
|
||||
* <p>Beginning with Android 3.0 (API level 11), the action bar appears at the top of an
|
||||
* activity's window when the activity uses the system's {@link
|
||||
* android.R.style#Theme_Holo Holo} theme (or one of its descendant themes), which is the default.
|
||||
* You may otherwise add the action bar by calling {@link
|
||||
* android.view.Window#requestFeature requestFeature(FEATURE_ACTION_BAR)} or by declaring it in a
|
||||
* custom theme with the {@link android.R.styleable#Theme_windowActionBar windowActionBar} property.
|
||||
* <p>By default, the action bar shows the application icon on
|
||||
* the left, followed by the activity title. If your activity has an options menu, you can make
|
||||
* select items accessible directly from the action bar as "action items". You can also
|
||||
* modify various characteristics of the action bar or remove it completely.</p>
|
||||
* <p>From your activity, you can retrieve an instance of {@link ActionBar} by calling {@link
|
||||
* android.app.Activity#getActionBar getActionBar()}.</p>
|
||||
* <p>In some cases, the action bar may be overlayed by another bar that enables contextual actions,
|
||||
* using an {@link android.view.ActionMode}. For example, when the user selects one or more items in
|
||||
* your activity, you can enable an action mode that offers actions specific to the selected
|
||||
* items, with a UI that temporarily replaces the action bar. Although the UI may occupy the
|
||||
* same space, the {@link android.view.ActionMode} APIs are distinct and independent from those for
|
||||
* {@link ActionBar}.
|
||||
* <div class="special reference">
|
||||
* <h3>Developer Guides</h3>
|
||||
* <p>For information about how to use the action bar, including how to add action items, navigation
|
||||
* modes and more, read the <a href="{@docRoot}guide/topics/ui/actionbar.html">Action
|
||||
* Bar</a> developer guide.</p>
|
||||
* </div>
|
||||
*/
|
||||
public abstract class ActionBar {
|
||||
/**
|
||||
* Standard navigation mode. Consists of either a logo or icon
|
||||
* and title text with an optional subtitle. Clicking any of these elements
|
||||
* will dispatch onOptionsItemSelected to the host Activity with
|
||||
* a MenuItem with item ID android.R.id.home.
|
||||
*/
|
||||
public static final int NAVIGATION_MODE_STANDARD = android.app.ActionBar.NAVIGATION_MODE_STANDARD;
|
||||
|
||||
/**
|
||||
* List navigation mode. Instead of static title text this mode
|
||||
* presents a list menu for navigation within the activity.
|
||||
* e.g. this might be presented to the user as a dropdown list.
|
||||
*/
|
||||
public static final int NAVIGATION_MODE_LIST = android.app.ActionBar.NAVIGATION_MODE_LIST;
|
||||
|
||||
/**
|
||||
* Tab navigation mode. Instead of static title text this mode
|
||||
* presents a series of tabs for navigation within the activity.
|
||||
*/
|
||||
public static final int NAVIGATION_MODE_TABS = android.app.ActionBar.NAVIGATION_MODE_TABS;
|
||||
|
||||
/**
|
||||
* Use logo instead of icon if available. This flag will cause appropriate
|
||||
* navigation modes to use a wider logo in place of the standard icon.
|
||||
*
|
||||
* @see #setDisplayOptions(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public static final int DISPLAY_USE_LOGO = android.app.ActionBar.DISPLAY_USE_LOGO;
|
||||
|
||||
/**
|
||||
* Show 'home' elements in this action bar, leaving more space for other
|
||||
* navigation elements. This includes logo and icon.
|
||||
*
|
||||
* @see #setDisplayOptions(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public static final int DISPLAY_SHOW_HOME = android.app.ActionBar.DISPLAY_SHOW_HOME;
|
||||
|
||||
/**
|
||||
* Display the 'home' element such that it appears as an 'up' affordance.
|
||||
* e.g. show an arrow to the left indicating the action that will be taken.
|
||||
*
|
||||
* Set this flag if selecting the 'home' button in the action bar to return
|
||||
* up by a single level in your UI rather than back to the top level or front page.
|
||||
*
|
||||
* <p>Setting this option will implicitly enable interaction with the home/up
|
||||
* button. See {@link #setHomeButtonEnabled(boolean)}.
|
||||
*
|
||||
* @see #setDisplayOptions(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public static final int DISPLAY_HOME_AS_UP = android.app.ActionBar.DISPLAY_HOME_AS_UP;
|
||||
|
||||
/**
|
||||
* Show the activity title and subtitle, if present.
|
||||
*
|
||||
* @see #setTitle(CharSequence)
|
||||
* @see #setTitle(int)
|
||||
* @see #setSubtitle(CharSequence)
|
||||
* @see #setSubtitle(int)
|
||||
* @see #setDisplayOptions(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public static final int DISPLAY_SHOW_TITLE = android.app.ActionBar.DISPLAY_SHOW_TITLE;
|
||||
|
||||
/**
|
||||
* Show the custom view if one has been set.
|
||||
* @see #setCustomView(View)
|
||||
* @see #setDisplayOptions(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public static final int DISPLAY_SHOW_CUSTOM = android.app.ActionBar.DISPLAY_SHOW_CUSTOM;
|
||||
|
||||
/**
|
||||
* Set the action bar into custom navigation mode, supplying a view
|
||||
* for custom navigation.
|
||||
*
|
||||
* Custom navigation views appear between the application icon and
|
||||
* any action buttons and may use any space available there. Common
|
||||
* use cases for custom navigation views might include an auto-suggesting
|
||||
* address bar for a browser or other navigation mechanisms that do not
|
||||
* translate well to provided navigation modes.
|
||||
*
|
||||
* @param view Custom navigation view to place in the ActionBar.
|
||||
*/
|
||||
public abstract void setCustomView(View view);
|
||||
|
||||
/**
|
||||
* Set the action bar into custom navigation mode, supplying a view
|
||||
* for custom navigation.
|
||||
*
|
||||
* <p>Custom navigation views appear between the application icon and
|
||||
* any action buttons and may use any space available there. Common
|
||||
* use cases for custom navigation views might include an auto-suggesting
|
||||
* address bar for a browser or other navigation mechanisms that do not
|
||||
* translate well to provided navigation modes.</p>
|
||||
*
|
||||
* <p>The display option {@link #DISPLAY_SHOW_CUSTOM} must be set for
|
||||
* the custom view to be displayed.</p>
|
||||
*
|
||||
* @param view Custom navigation view to place in the ActionBar.
|
||||
* @param layoutParams How this custom view should layout in the bar.
|
||||
*
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public abstract void setCustomView(View view, LayoutParams layoutParams);
|
||||
|
||||
/**
|
||||
* Set the action bar into custom navigation mode, supplying a view
|
||||
* for custom navigation.
|
||||
*
|
||||
* <p>Custom navigation views appear between the application icon and
|
||||
* any action buttons and may use any space available there. Common
|
||||
* use cases for custom navigation views might include an auto-suggesting
|
||||
* address bar for a browser or other navigation mechanisms that do not
|
||||
* translate well to provided navigation modes.</p>
|
||||
*
|
||||
* <p>The display option {@link #DISPLAY_SHOW_CUSTOM} must be set for
|
||||
* the custom view to be displayed.</p>
|
||||
*
|
||||
* @param resId Resource ID of a layout to inflate into the ActionBar.
|
||||
*
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public abstract void setCustomView(int resId);
|
||||
|
||||
/**
|
||||
* Set the icon to display in the 'home' section of the action bar.
|
||||
* The action bar will use an icon specified by its style or the
|
||||
* activity icon by default.
|
||||
*
|
||||
* Whether the home section shows an icon or logo is controlled
|
||||
* by the display option {@link #DISPLAY_USE_LOGO}.
|
||||
*
|
||||
* @param resId Resource ID of a drawable to show as an icon.
|
||||
*
|
||||
* @see #setDisplayUseLogoEnabled(boolean)
|
||||
* @see #setDisplayShowHomeEnabled(boolean)
|
||||
*/
|
||||
public abstract void setIcon(int resId);
|
||||
|
||||
/**
|
||||
* Set the icon to display in the 'home' section of the action bar.
|
||||
* The action bar will use an icon specified by its style or the
|
||||
* activity icon by default.
|
||||
*
|
||||
* Whether the home section shows an icon or logo is controlled
|
||||
* by the display option {@link #DISPLAY_USE_LOGO}.
|
||||
*
|
||||
* @param icon Drawable to show as an icon.
|
||||
*
|
||||
* @see #setDisplayUseLogoEnabled(boolean)
|
||||
* @see #setDisplayShowHomeEnabled(boolean)
|
||||
*/
|
||||
public abstract void setIcon(Drawable icon);
|
||||
|
||||
/**
|
||||
* Set the logo to display in the 'home' section of the action bar.
|
||||
* The action bar will use a logo specified by its style or the
|
||||
* activity logo by default.
|
||||
*
|
||||
* Whether the home section shows an icon or logo is controlled
|
||||
* by the display option {@link #DISPLAY_USE_LOGO}.
|
||||
*
|
||||
* @param resId Resource ID of a drawable to show as a logo.
|
||||
*
|
||||
* @see #setDisplayUseLogoEnabled(boolean)
|
||||
* @see #setDisplayShowHomeEnabled(boolean)
|
||||
*/
|
||||
public abstract void setLogo(int resId);
|
||||
|
||||
/**
|
||||
* Set the logo to display in the 'home' section of the action bar.
|
||||
* The action bar will use a logo specified by its style or the
|
||||
* activity logo by default.
|
||||
*
|
||||
* Whether the home section shows an icon or logo is controlled
|
||||
* by the display option {@link #DISPLAY_USE_LOGO}.
|
||||
*
|
||||
* @param logo Drawable to show as a logo.
|
||||
*
|
||||
* @see #setDisplayUseLogoEnabled(boolean)
|
||||
* @see #setDisplayShowHomeEnabled(boolean)
|
||||
*/
|
||||
public abstract void setLogo(Drawable logo);
|
||||
|
||||
/**
|
||||
* Set the adapter and navigation callback for list navigation mode.
|
||||
*
|
||||
* The supplied adapter will provide views for the expanded list as well as
|
||||
* the currently selected item. (These may be displayed differently.)
|
||||
*
|
||||
* The supplied OnNavigationListener will alert the application when the user
|
||||
* changes the current list selection.
|
||||
*
|
||||
* @param adapter An adapter that will provide views both to display
|
||||
* the current navigation selection and populate views
|
||||
* within the dropdown navigation menu.
|
||||
* @param callback An OnNavigationListener that will receive events when the user
|
||||
* selects a navigation item.
|
||||
*/
|
||||
public abstract void setListNavigationCallbacks(SpinnerAdapter adapter,
|
||||
OnNavigationListener callback);
|
||||
|
||||
/**
|
||||
* Set the selected navigation item in list or tabbed navigation modes.
|
||||
*
|
||||
* @param position Position of the item to select.
|
||||
*/
|
||||
public abstract void setSelectedNavigationItem(int position);
|
||||
|
||||
/**
|
||||
* Get the position of the selected navigation item in list or tabbed navigation modes.
|
||||
*
|
||||
* @return Position of the selected item.
|
||||
*/
|
||||
public abstract int getSelectedNavigationIndex();
|
||||
|
||||
/**
|
||||
* Get the number of navigation items present in the current navigation mode.
|
||||
*
|
||||
* @return Number of navigation items.
|
||||
*/
|
||||
public abstract int getNavigationItemCount();
|
||||
|
||||
/**
|
||||
* Set the action bar's title. This will only be displayed if
|
||||
* {@link #DISPLAY_SHOW_TITLE} is set.
|
||||
*
|
||||
* @param title Title to set
|
||||
*
|
||||
* @see #setTitle(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public abstract void setTitle(CharSequence title);
|
||||
|
||||
/**
|
||||
* Set the action bar's title. This will only be displayed if
|
||||
* {@link #DISPLAY_SHOW_TITLE} is set.
|
||||
*
|
||||
* @param resId Resource ID of title string to set
|
||||
*
|
||||
* @see #setTitle(CharSequence)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public abstract void setTitle(int resId);
|
||||
|
||||
/**
|
||||
* Set the action bar's subtitle. This will only be displayed if
|
||||
* {@link #DISPLAY_SHOW_TITLE} is set. Set to null to disable the
|
||||
* subtitle entirely.
|
||||
*
|
||||
* @param subtitle Subtitle to set
|
||||
*
|
||||
* @see #setSubtitle(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public abstract void setSubtitle(CharSequence subtitle);
|
||||
|
||||
/**
|
||||
* Set the action bar's subtitle. This will only be displayed if
|
||||
* {@link #DISPLAY_SHOW_TITLE} is set.
|
||||
*
|
||||
* @param resId Resource ID of subtitle string to set
|
||||
*
|
||||
* @see #setSubtitle(CharSequence)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public abstract void setSubtitle(int resId);
|
||||
|
||||
/**
|
||||
* Set display options. This changes all display option bits at once. To change
|
||||
* a limited subset of display options, see {@link #setDisplayOptions(int, int)}.
|
||||
*
|
||||
* @param options A combination of the bits defined by the DISPLAY_ constants
|
||||
* defined in ActionBar.
|
||||
*/
|
||||
public abstract void setDisplayOptions(int options);
|
||||
|
||||
/**
|
||||
* Set selected display options. Only the options specified by mask will be changed.
|
||||
* To change all display option bits at once, see {@link #setDisplayOptions(int)}.
|
||||
*
|
||||
* <p>Example: setDisplayOptions(0, DISPLAY_SHOW_HOME) will disable the
|
||||
* {@link #DISPLAY_SHOW_HOME} option.
|
||||
* setDisplayOptions(DISPLAY_SHOW_HOME, DISPLAY_SHOW_HOME | DISPLAY_USE_LOGO)
|
||||
* will enable {@link #DISPLAY_SHOW_HOME} and disable {@link #DISPLAY_USE_LOGO}.
|
||||
*
|
||||
* @param options A combination of the bits defined by the DISPLAY_ constants
|
||||
* defined in ActionBar.
|
||||
* @param mask A bit mask declaring which display options should be changed.
|
||||
*/
|
||||
public abstract void setDisplayOptions(int options, int mask);
|
||||
|
||||
/**
|
||||
* Set whether to display the activity logo rather than the activity icon.
|
||||
* A logo is often a wider, more detailed image.
|
||||
*
|
||||
* <p>To set several display options at once, see the setDisplayOptions methods.
|
||||
*
|
||||
* @param useLogo true to use the activity logo, false to use the activity icon.
|
||||
*
|
||||
* @see #setDisplayOptions(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public abstract void setDisplayUseLogoEnabled(boolean useLogo);
|
||||
|
||||
/**
|
||||
* Set whether to include the application home affordance in the action bar.
|
||||
* Home is presented as either an activity icon or logo.
|
||||
*
|
||||
* <p>To set several display options at once, see the setDisplayOptions methods.
|
||||
*
|
||||
* @param showHome true to show home, false otherwise.
|
||||
*
|
||||
* @see #setDisplayOptions(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public abstract void setDisplayShowHomeEnabled(boolean showHome);
|
||||
|
||||
/**
|
||||
* Set whether home should be displayed as an "up" affordance.
|
||||
* Set this to true if selecting "home" returns up by a single level in your UI
|
||||
* rather than back to the top level or front page.
|
||||
*
|
||||
* <p>To set several display options at once, see the setDisplayOptions methods.
|
||||
*
|
||||
* @param showHomeAsUp true to show the user that selecting home will return one
|
||||
* level up rather than to the top level of the app.
|
||||
*
|
||||
* @see #setDisplayOptions(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public abstract void setDisplayHomeAsUpEnabled(boolean showHomeAsUp);
|
||||
|
||||
/**
|
||||
* Set whether an activity title/subtitle should be displayed.
|
||||
*
|
||||
* <p>To set several display options at once, see the setDisplayOptions methods.
|
||||
*
|
||||
* @param showTitle true to display a title/subtitle if present.
|
||||
*
|
||||
* @see #setDisplayOptions(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public abstract void setDisplayShowTitleEnabled(boolean showTitle);
|
||||
|
||||
/**
|
||||
* Set whether a custom view should be displayed, if set.
|
||||
*
|
||||
* <p>To set several display options at once, see the setDisplayOptions methods.
|
||||
*
|
||||
* @param showCustom true if the currently set custom view should be displayed, false otherwise.
|
||||
*
|
||||
* @see #setDisplayOptions(int)
|
||||
* @see #setDisplayOptions(int, int)
|
||||
*/
|
||||
public abstract void setDisplayShowCustomEnabled(boolean showCustom);
|
||||
|
||||
/**
|
||||
* Set the ActionBar's background. This will be used for the primary
|
||||
* action bar.
|
||||
*
|
||||
* @param d Background drawable
|
||||
* @see #setStackedBackgroundDrawable(Drawable)
|
||||
* @see #setSplitBackgroundDrawable(Drawable)
|
||||
*/
|
||||
public abstract void setBackgroundDrawable(Drawable d);
|
||||
|
||||
/**
|
||||
* Set the ActionBar's stacked background. This will appear
|
||||
* in the second row/stacked bar on some devices and configurations.
|
||||
*
|
||||
* @param d Background drawable for the stacked row
|
||||
*/
|
||||
public void setStackedBackgroundDrawable(Drawable d) { }
|
||||
|
||||
/**
|
||||
* Set the ActionBar's split background. This will appear in
|
||||
* the split action bar containing menu-provided action buttons
|
||||
* on some devices and configurations.
|
||||
* <p>You can enable split action bar with {@link android.R.attr#uiOptions}
|
||||
*
|
||||
* @param d Background drawable for the split bar
|
||||
*/
|
||||
public void setSplitBackgroundDrawable(Drawable d) { }
|
||||
|
||||
/**
|
||||
* @return The current custom view.
|
||||
*/
|
||||
public abstract View getCustomView();
|
||||
|
||||
/**
|
||||
* Returns the current ActionBar title in standard mode.
|
||||
* Returns null if {@link #getNavigationMode()} would not return
|
||||
* {@link #NAVIGATION_MODE_STANDARD}.
|
||||
*
|
||||
* @return The current ActionBar title or null.
|
||||
*/
|
||||
public abstract CharSequence getTitle();
|
||||
|
||||
/**
|
||||
* Returns the current ActionBar subtitle in standard mode.
|
||||
* Returns null if {@link #getNavigationMode()} would not return
|
||||
* {@link #NAVIGATION_MODE_STANDARD}.
|
||||
*
|
||||
* @return The current ActionBar subtitle or null.
|
||||
*/
|
||||
public abstract CharSequence getSubtitle();
|
||||
|
||||
/**
|
||||
* Returns the current navigation mode. The result will be one of:
|
||||
* <ul>
|
||||
* <li>{@link #NAVIGATION_MODE_STANDARD}</li>
|
||||
* <li>{@link #NAVIGATION_MODE_LIST}</li>
|
||||
* <li>{@link #NAVIGATION_MODE_TABS}</li>
|
||||
* </ul>
|
||||
*
|
||||
* @return The current navigation mode.
|
||||
*/
|
||||
public abstract int getNavigationMode();
|
||||
|
||||
/**
|
||||
* Set the current navigation mode.
|
||||
*
|
||||
* @param mode The new mode to set.
|
||||
* @see #NAVIGATION_MODE_STANDARD
|
||||
* @see #NAVIGATION_MODE_LIST
|
||||
* @see #NAVIGATION_MODE_TABS
|
||||
*/
|
||||
public abstract void setNavigationMode(int mode);
|
||||
|
||||
/**
|
||||
* @return The current set of display options.
|
||||
*/
|
||||
public abstract int getDisplayOptions();
|
||||
|
||||
/**
|
||||
* Create and return a new {@link Tab}.
|
||||
* This tab will not be included in the action bar until it is added.
|
||||
*
|
||||
* <p>Very often tabs will be used to switch between {@link Fragment}
|
||||
* objects. Here is a typical implementation of such tabs:</p>
|
||||
*
|
||||
* {@sample development/samples/ApiDemos/src/com/example/android/apis/app/FragmentTabs.java
|
||||
* complete}
|
||||
*
|
||||
* @return A new Tab
|
||||
*
|
||||
* @see #addTab(Tab)
|
||||
*/
|
||||
public abstract Tab newTab();
|
||||
|
||||
/**
|
||||
* Add a tab for use in tabbed navigation mode. The tab will be added at the end of the list.
|
||||
* If this is the first tab to be added it will become the selected tab.
|
||||
*
|
||||
* @param tab Tab to add
|
||||
*/
|
||||
public abstract void addTab(Tab tab);
|
||||
|
||||
/**
|
||||
* Add a tab for use in tabbed navigation mode. The tab will be added at the end of the list.
|
||||
*
|
||||
* @param tab Tab to add
|
||||
* @param setSelected True if the added tab should become the selected tab.
|
||||
*/
|
||||
public abstract void addTab(Tab tab, boolean setSelected);
|
||||
|
||||
/**
|
||||
* Add a tab for use in tabbed navigation mode. The tab will be inserted at
|
||||
* <code>position</code>. If this is the first tab to be added it will become
|
||||
* the selected tab.
|
||||
*
|
||||
* @param tab The tab to add
|
||||
* @param position The new position of the tab
|
||||
*/
|
||||
public abstract void addTab(Tab tab, int position);
|
||||
|
||||
/**
|
||||
* Add a tab for use in tabbed navigation mode. The tab will be insterted at
|
||||
* <code>position</code>.
|
||||
*
|
||||
* @param tab The tab to add
|
||||
* @param position The new position of the tab
|
||||
* @param setSelected True if the added tab should become the selected tab.
|
||||
*/
|
||||
public abstract void addTab(Tab tab, int position, boolean setSelected);
|
||||
|
||||
/**
|
||||
* Remove a tab from the action bar. If the removed tab was selected it will be deselected
|
||||
* and another tab will be selected if present.
|
||||
*
|
||||
* @param tab The tab to remove
|
||||
*/
|
||||
public abstract void removeTab(Tab tab);
|
||||
|
||||
/**
|
||||
* Remove a tab from the action bar. If the removed tab was selected it will be deselected
|
||||
* and another tab will be selected if present.
|
||||
*
|
||||
* @param position Position of the tab to remove
|
||||
*/
|
||||
public abstract void removeTabAt(int position);
|
||||
|
||||
/**
|
||||
* Remove all tabs from the action bar and deselect the current tab.
|
||||
*/
|
||||
public abstract void removeAllTabs();
|
||||
|
||||
/**
|
||||
* Select the specified tab. If it is not a child of this action bar it will be added.
|
||||
*
|
||||
* <p>Note: If you want to select by index, use {@link #setSelectedNavigationItem(int)}.</p>
|
||||
*
|
||||
* @param tab Tab to select
|
||||
*/
|
||||
public abstract void selectTab(Tab tab);
|
||||
|
||||
/**
|
||||
* Returns the currently selected tab if in tabbed navigation mode and there is at least
|
||||
* one tab present.
|
||||
*
|
||||
* @return The currently selected tab or null
|
||||
*/
|
||||
public abstract Tab getSelectedTab();
|
||||
|
||||
/**
|
||||
* Returns the tab at the specified index.
|
||||
*
|
||||
* @param index Index value in the range 0-get
|
||||
* @return
|
||||
*/
|
||||
public abstract Tab getTabAt(int index);
|
||||
|
||||
/**
|
||||
* Returns the number of tabs currently registered with the action bar.
|
||||
* @return Tab count
|
||||
*/
|
||||
public abstract int getTabCount();
|
||||
|
||||
/**
|
||||
* Retrieve the current height of the ActionBar.
|
||||
*
|
||||
* @return The ActionBar's height
|
||||
*/
|
||||
public abstract int getHeight();
|
||||
|
||||
/**
|
||||
* Show the ActionBar if it is not currently showing.
|
||||
* If the window hosting the ActionBar does not have the feature
|
||||
* {@link Window#FEATURE_ACTION_BAR_OVERLAY} it will resize application
|
||||
* content to fit the new space available.
|
||||
*/
|
||||
public abstract void show();
|
||||
|
||||
/**
|
||||
* Hide the ActionBar if it is currently showing.
|
||||
* If the window hosting the ActionBar does not have the feature
|
||||
* {@link Window#FEATURE_ACTION_BAR_OVERLAY} it will resize application
|
||||
* content to fit the new space available.
|
||||
*/
|
||||
public abstract void hide();
|
||||
|
||||
/**
|
||||
* @return <code>true</code> if the ActionBar is showing, <code>false</code> otherwise.
|
||||
*/
|
||||
public abstract boolean isShowing();
|
||||
|
||||
/**
|
||||
* Add a listener that will respond to menu visibility change events.
|
||||
*
|
||||
* @param listener The new listener to add
|
||||
*/
|
||||
public abstract void addOnMenuVisibilityListener(OnMenuVisibilityListener listener);
|
||||
|
||||
/**
|
||||
* Remove a menu visibility listener. This listener will no longer receive menu
|
||||
* visibility change events.
|
||||
*
|
||||
* @param listener A listener to remove that was previously added
|
||||
*/
|
||||
public abstract void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener);
|
||||
|
||||
/**
|
||||
* Enable or disable the "home" button in the corner of the action bar. (Note that this
|
||||
* is the application home/up affordance on the action bar, not the systemwide home
|
||||
* button.)
|
||||
*
|
||||
* <p>This defaults to true for packages targeting < API 14. For packages targeting
|
||||
* API 14 or greater, the application should call this method to enable interaction
|
||||
* with the home/up affordance.
|
||||
*
|
||||
* <p>Setting the {@link #DISPLAY_HOME_AS_UP} display option will automatically enable
|
||||
* the home button.
|
||||
*
|
||||
* @param enabled true to enable the home button, false to disable the home button.
|
||||
*/
|
||||
public void setHomeButtonEnabled(boolean enabled) { }
|
||||
|
||||
/**
|
||||
* Returns a {@link Context} with an appropriate theme for creating views that
|
||||
* will appear in the action bar. If you are inflating or instantiating custom views
|
||||
* that will appear in an action bar, you should use the Context returned by this method.
|
||||
* (This includes adapters used for list navigation mode.)
|
||||
* This will ensure that views contrast properly against the action bar.
|
||||
*
|
||||
* @return A themed Context for creating views
|
||||
*/
|
||||
public Context getThemedContext() { return null; }
|
||||
|
||||
/**
|
||||
* Listener interface for ActionBar navigation events.
|
||||
*/
|
||||
public interface OnNavigationListener {
|
||||
/**
|
||||
* This method is called whenever a navigation item in your action bar
|
||||
* is selected.
|
||||
*
|
||||
* @param itemPosition Position of the item clicked.
|
||||
* @param itemId ID of the item clicked.
|
||||
* @return True if the event was handled, false otherwise.
|
||||
*/
|
||||
public boolean onNavigationItemSelected(int itemPosition, long itemId);
|
||||
}
|
||||
|
||||
/**
|
||||
* Listener for receiving events when action bar menus are shown or hidden.
|
||||
*/
|
||||
public interface OnMenuVisibilityListener {
|
||||
/**
|
||||
* Called when an action bar menu is shown or hidden. Applications may want to use
|
||||
* this to tune auto-hiding behavior for the action bar or pause/resume video playback,
|
||||
* gameplay, or other activity within the main content area.
|
||||
*
|
||||
* @param isVisible True if an action bar menu is now visible, false if no action bar
|
||||
* menus are visible.
|
||||
*/
|
||||
public void onMenuVisibilityChanged(boolean isVisible);
|
||||
}
|
||||
|
||||
/**
|
||||
* A tab in the action bar.
|
||||
*
|
||||
* <p>Tabs manage the hiding and showing of {@link Fragment}s.
|
||||
*/
|
||||
public static abstract class Tab {
|
||||
/**
|
||||
* An invalid position for a tab.
|
||||
*
|
||||
* @see #getPosition()
|
||||
*/
|
||||
public static final int INVALID_POSITION = -1;
|
||||
|
||||
/**
|
||||
* Return the current position of this tab in the action bar.
|
||||
*
|
||||
* @return Current position, or {@link #INVALID_POSITION} if this tab is not currently in
|
||||
* the action bar.
|
||||
*/
|
||||
public abstract int getPosition();
|
||||
|
||||
/**
|
||||
* Return the icon associated with this tab.
|
||||
*
|
||||
* @return The tab's icon
|
||||
*/
|
||||
public abstract Drawable getIcon();
|
||||
|
||||
/**
|
||||
* Return the text of this tab.
|
||||
*
|
||||
* @return The tab's text
|
||||
*/
|
||||
public abstract CharSequence getText();
|
||||
|
||||
/**
|
||||
* Set the icon displayed on this tab.
|
||||
*
|
||||
* @param icon The drawable to use as an icon
|
||||
* @return The current instance for call chaining
|
||||
*/
|
||||
public abstract Tab setIcon(Drawable icon);
|
||||
|
||||
/**
|
||||
* Set the icon displayed on this tab.
|
||||
*
|
||||
* @param resId Resource ID referring to the drawable to use as an icon
|
||||
* @return The current instance for call chaining
|
||||
*/
|
||||
public abstract Tab setIcon(int resId);
|
||||
|
||||
/**
|
||||
* Set the text displayed on this tab. Text may be truncated if there is not
|
||||
* room to display the entire string.
|
||||
*
|
||||
* @param text The text to display
|
||||
* @return The current instance for call chaining
|
||||
*/
|
||||
public abstract Tab setText(CharSequence text);
|
||||
|
||||
/**
|
||||
* Set the text displayed on this tab. Text may be truncated if there is not
|
||||
* room to display the entire string.
|
||||
*
|
||||
* @param resId A resource ID referring to the text that should be displayed
|
||||
* @return The current instance for call chaining
|
||||
*/
|
||||
public abstract Tab setText(int resId);
|
||||
|
||||
/**
|
||||
* Set a custom view to be used for this tab. This overrides values set by
|
||||
* {@link #setText(CharSequence)} and {@link #setIcon(Drawable)}.
|
||||
*
|
||||
* @param view Custom view to be used as a tab.
|
||||
* @return The current instance for call chaining
|
||||
*/
|
||||
public abstract Tab setCustomView(View view);
|
||||
|
||||
/**
|
||||
* Set a custom view to be used for this tab. This overrides values set by
|
||||
* {@link #setText(CharSequence)} and {@link #setIcon(Drawable)}.
|
||||
*
|
||||
* @param layoutResId A layout resource to inflate and use as a custom tab view
|
||||
* @return The current instance for call chaining
|
||||
*/
|
||||
public abstract Tab setCustomView(int layoutResId);
|
||||
|
||||
/**
|
||||
* Retrieve a previously set custom view for this tab.
|
||||
*
|
||||
* @return The custom view set by {@link #setCustomView(View)}.
|
||||
*/
|
||||
public abstract View getCustomView();
|
||||
|
||||
/**
|
||||
* Give this Tab an arbitrary object to hold for later use.
|
||||
*
|
||||
* @param obj Object to store
|
||||
* @return The current instance for call chaining
|
||||
*/
|
||||
public abstract Tab setTag(Object obj);
|
||||
|
||||
/**
|
||||
* @return This Tab's tag object.
|
||||
*/
|
||||
public abstract Object getTag();
|
||||
|
||||
/**
|
||||
* Set the {@link TabListener} that will handle switching to and from this tab.
|
||||
* All tabs must have a TabListener set before being added to the ActionBar.
|
||||
*
|
||||
* @param listener Listener to handle tab selection events
|
||||
* @return The current instance for call chaining
|
||||
*/
|
||||
public abstract Tab setTabListener(TabListener listener);
|
||||
|
||||
/**
|
||||
* Select this tab. Only valid if the tab has been added to the action bar.
|
||||
*/
|
||||
public abstract void select();
|
||||
|
||||
/**
|
||||
* Set a description of this tab's content for use in accessibility support.
|
||||
* If no content description is provided the title will be used.
|
||||
*
|
||||
* @param resId A resource ID referring to the description text
|
||||
* @return The current instance for call chaining
|
||||
* @see #setContentDescription(CharSequence)
|
||||
* @see #getContentDescription()
|
||||
*/
|
||||
public abstract Tab setContentDescription(int resId);
|
||||
|
||||
/**
|
||||
* Set a description of this tab's content for use in accessibility support.
|
||||
* If no content description is provided the title will be used.
|
||||
*
|
||||
* @param contentDesc Description of this tab's content
|
||||
* @return The current instance for call chaining
|
||||
* @see #setContentDescription(int)
|
||||
* @see #getContentDescription()
|
||||
*/
|
||||
public abstract Tab setContentDescription(CharSequence contentDesc);
|
||||
|
||||
/**
|
||||
* Gets a brief description of this tab's content for use in accessibility support.
|
||||
*
|
||||
* @return Description of this tab's content
|
||||
* @see #setContentDescription(CharSequence)
|
||||
* @see #setContentDescription(int)
|
||||
*/
|
||||
public abstract CharSequence getContentDescription();
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback interface invoked when a tab is focused, unfocused, added, or removed.
|
||||
*/
|
||||
public interface TabListener {
|
||||
/**
|
||||
* Called when a tab enters the selected state.
|
||||
*
|
||||
* @param tab The tab that was selected
|
||||
* @param ft A {@link FragmentTransaction} for queuing fragment operations to execute
|
||||
* during a tab switch. The previous tab's unselect and this tab's select will be
|
||||
* executed in a single transaction. This FragmentTransaction does not support
|
||||
* being added to the back stack.
|
||||
*/
|
||||
public void onTabSelected(Tab tab, FragmentTransaction ft);
|
||||
|
||||
/**
|
||||
* Called when a tab exits the selected state.
|
||||
*
|
||||
* @param tab The tab that was unselected
|
||||
* @param ft A {@link FragmentTransaction} for queuing fragment operations to execute
|
||||
* during a tab switch. This tab's unselect and the newly selected tab's select
|
||||
* will be executed in a single transaction. This FragmentTransaction does not
|
||||
* support being added to the back stack.
|
||||
*/
|
||||
public void onTabUnselected(Tab tab, FragmentTransaction ft);
|
||||
|
||||
/**
|
||||
* Called when a tab that is already selected is chosen again by the user.
|
||||
* Some applications may use this action to return to the top level of a category.
|
||||
*
|
||||
* @param tab The tab that was reselected.
|
||||
* @param ft A {@link FragmentTransaction} for queuing fragment operations to execute
|
||||
* once this method returns. This FragmentTransaction does not support
|
||||
* being added to the back stack.
|
||||
*/
|
||||
public void onTabReselected(Tab tab, FragmentTransaction ft);
|
||||
}
|
||||
|
||||
/**
|
||||
* Per-child layout information associated with action bar custom views.
|
||||
*
|
||||
* @attr ref android.R.styleable#ActionBar_LayoutParams_layout_gravity
|
||||
*/
|
||||
public static class LayoutParams extends MarginLayoutParams {
|
||||
private static final int[] ATTRS = new int[] {
|
||||
android.R.attr.layout_gravity
|
||||
};
|
||||
|
||||
/**
|
||||
* Gravity for the view associated with these LayoutParams.
|
||||
*
|
||||
* @see android.view.Gravity
|
||||
*/
|
||||
@ViewDebug.ExportedProperty(mapping = {
|
||||
@ViewDebug.IntToString(from = -1, to = "NONE"),
|
||||
@ViewDebug.IntToString(from = Gravity.NO_GRAVITY, to = "NONE"),
|
||||
@ViewDebug.IntToString(from = Gravity.TOP, to = "TOP"),
|
||||
@ViewDebug.IntToString(from = Gravity.BOTTOM, to = "BOTTOM"),
|
||||
@ViewDebug.IntToString(from = Gravity.LEFT, to = "LEFT"),
|
||||
@ViewDebug.IntToString(from = Gravity.RIGHT, to = "RIGHT"),
|
||||
@ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL, to = "CENTER_VERTICAL"),
|
||||
@ViewDebug.IntToString(from = Gravity.FILL_VERTICAL, to = "FILL_VERTICAL"),
|
||||
@ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
|
||||
@ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL, to = "FILL_HORIZONTAL"),
|
||||
@ViewDebug.IntToString(from = Gravity.CENTER, to = "CENTER"),
|
||||
@ViewDebug.IntToString(from = Gravity.FILL, to = "FILL")
|
||||
})
|
||||
public int gravity = -1;
|
||||
|
||||
public LayoutParams(Context c, AttributeSet attrs) {
|
||||
super(c, attrs);
|
||||
|
||||
TypedArray a = c.obtainStyledAttributes(attrs, ATTRS);
|
||||
gravity = a.getInt(0, -1);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
public LayoutParams(int width, int height) {
|
||||
super(width, height);
|
||||
this.gravity = Gravity.CENTER_VERTICAL | Gravity.LEFT;
|
||||
}
|
||||
|
||||
public LayoutParams(int width, int height, int gravity) {
|
||||
super(width, height);
|
||||
this.gravity = gravity;
|
||||
}
|
||||
|
||||
public LayoutParams(int gravity) {
|
||||
this(WRAP_CONTENT, FILL_PARENT, gravity);
|
||||
}
|
||||
|
||||
public LayoutParams(LayoutParams source) {
|
||||
super(source);
|
||||
|
||||
this.gravity = source.gravity;
|
||||
}
|
||||
|
||||
public LayoutParams(ViewGroup.LayoutParams source) {
|
||||
super(source);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,276 +0,0 @@
|
|||
package com.actionbarsherlock.app;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import com.actionbarsherlock.ActionBarSherlock;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnActionModeFinishedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnActionModeStartedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnCreatePanelMenuListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnMenuItemSelectedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnPreparePanelListener;
|
||||
import com.actionbarsherlock.view.ActionMode;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
public abstract class SherlockActivity extends Activity implements OnCreatePanelMenuListener, OnPreparePanelListener, OnMenuItemSelectedListener, OnActionModeStartedListener, OnActionModeFinishedListener {
|
||||
private ActionBarSherlock mSherlock;
|
||||
|
||||
protected final ActionBarSherlock getSherlock() {
|
||||
if (mSherlock == null) {
|
||||
mSherlock = ActionBarSherlock.wrap(this, ActionBarSherlock.FLAG_DELEGATE);
|
||||
}
|
||||
return mSherlock;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Action bar and mode
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public ActionBar getSupportActionBar() {
|
||||
return getSherlock().getActionBar();
|
||||
}
|
||||
|
||||
public ActionMode startActionMode(ActionMode.Callback callback) {
|
||||
return getSherlock().startActionMode(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionModeStarted(ActionMode mode) {}
|
||||
|
||||
@Override
|
||||
public void onActionModeFinished(ActionMode mode) {}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// General lifecycle/callback dispatching
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
getSherlock().dispatchConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostResume() {
|
||||
super.onPostResume();
|
||||
getSherlock().dispatchPostResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
getSherlock().dispatchPause();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
getSherlock().dispatchStop();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
getSherlock().dispatchDestroy();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
getSherlock().dispatchPostCreate(savedInstanceState);
|
||||
super.onPostCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTitleChanged(CharSequence title, int color) {
|
||||
getSherlock().dispatchTitleChanged(title, color);
|
||||
super.onTitleChanged(title, color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onMenuOpened(int featureId, android.view.Menu menu) {
|
||||
if (getSherlock().dispatchMenuOpened(featureId, menu)) {
|
||||
return true;
|
||||
}
|
||||
return super.onMenuOpened(featureId, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPanelClosed(int featureId, android.view.Menu menu) {
|
||||
getSherlock().dispatchPanelClosed(featureId, menu);
|
||||
super.onPanelClosed(featureId, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (getSherlock().dispatchKeyEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
getSherlock().dispatchSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
getSherlock().dispatchRestoreInstanceState(savedInstanceState);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Native menu handling
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public MenuInflater getSupportMenuInflater() {
|
||||
return getSherlock().getMenuInflater();
|
||||
}
|
||||
|
||||
public void invalidateOptionsMenu() {
|
||||
getSherlock().dispatchInvalidateOptionsMenu();
|
||||
}
|
||||
|
||||
public void supportInvalidateOptionsMenu() {
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onCreateOptionsMenu(android.view.Menu menu) {
|
||||
return getSherlock().dispatchCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onPrepareOptionsMenu(android.view.Menu menu) {
|
||||
return getSherlock().dispatchPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onOptionsItemSelected(android.view.MenuItem item) {
|
||||
return getSherlock().dispatchOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openOptionsMenu() {
|
||||
if (!getSherlock().dispatchOpenOptionsMenu()) {
|
||||
super.openOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeOptionsMenu() {
|
||||
if (!getSherlock().dispatchCloseOptionsMenu()) {
|
||||
super.closeOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Sherlock menu handling
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public boolean onCreatePanelMenu(int featureId, Menu menu) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onCreateOptionsMenu(menu);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreparePanel(int featureId, View view, Menu menu) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onPrepareOptionsMenu(menu);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onOptionsItemSelected(item);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Content
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void addContentView(View view, LayoutParams params) {
|
||||
getSherlock().addContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(int layoutResId) {
|
||||
getSherlock().setContentView(layoutResId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view, LayoutParams params) {
|
||||
getSherlock().setContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view) {
|
||||
getSherlock().setContentView(view);
|
||||
}
|
||||
|
||||
public void requestWindowFeature(long featureId) {
|
||||
getSherlock().requestFeature((int)featureId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View findViewById(int id) {
|
||||
getSherlock().ensureActionBar();
|
||||
return super.findViewById(id);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Progress Indication
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void setSupportProgress(int progress) {
|
||||
getSherlock().setProgress(progress);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarIndeterminate(boolean indeterminate) {
|
||||
getSherlock().setProgressBarIndeterminate(indeterminate);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarIndeterminateVisibility(boolean visible) {
|
||||
getSherlock().setProgressBarIndeterminateVisibility(visible);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarVisibility(boolean visible) {
|
||||
getSherlock().setProgressBarVisibility(visible);
|
||||
}
|
||||
|
||||
public void setSupportSecondaryProgress(int secondaryProgress) {
|
||||
getSherlock().setSecondaryProgress(secondaryProgress);
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
package com.actionbarsherlock.app;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.support.v4.app.DialogFragment;
|
||||
import com.actionbarsherlock.internal.view.menu.MenuItemWrapper;
|
||||
import com.actionbarsherlock.internal.view.menu.MenuWrapper;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
import static android.support.v4.app.Watson.OnCreateOptionsMenuListener;
|
||||
import static android.support.v4.app.Watson.OnOptionsItemSelectedListener;
|
||||
import static android.support.v4.app.Watson.OnPrepareOptionsMenuListener;
|
||||
|
||||
public class SherlockDialogFragment extends DialogFragment implements OnCreateOptionsMenuListener, OnPrepareOptionsMenuListener, OnOptionsItemSelectedListener {
|
||||
private SherlockFragmentActivity mActivity;
|
||||
|
||||
public SherlockFragmentActivity getSherlockActivity() {
|
||||
return mActivity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
if (!(activity instanceof SherlockFragmentActivity)) {
|
||||
throw new IllegalStateException(getClass().getSimpleName() + " must be attached to a SherlockFragmentActivity.");
|
||||
}
|
||||
mActivity = (SherlockFragmentActivity)activity;
|
||||
|
||||
super.onAttach(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
mActivity = null;
|
||||
super.onDetach();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onCreateOptionsMenu(android.view.Menu menu, android.view.MenuInflater inflater) {
|
||||
onCreateOptionsMenu(new MenuWrapper(menu), mActivity.getSupportMenuInflater());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
//Nothing to see here.
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onPrepareOptionsMenu(android.view.Menu menu) {
|
||||
onPrepareOptionsMenu(new MenuWrapper(menu));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
//Nothing to see here.
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onOptionsItemSelected(android.view.MenuItem item) {
|
||||
return onOptionsItemSelected(new MenuItemWrapper(item));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
//Nothing to see here.
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,265 +0,0 @@
|
|||
package com.actionbarsherlock.app;
|
||||
|
||||
import android.app.ExpandableListActivity;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.view.Window;
|
||||
import com.actionbarsherlock.ActionBarSherlock;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnActionModeFinishedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnActionModeStartedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnCreatePanelMenuListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnMenuItemSelectedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnPreparePanelListener;
|
||||
import com.actionbarsherlock.view.ActionMode;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
public abstract class SherlockExpandableListActivity extends ExpandableListActivity implements OnCreatePanelMenuListener, OnPreparePanelListener, OnMenuItemSelectedListener, OnActionModeStartedListener, OnActionModeFinishedListener {
|
||||
private ActionBarSherlock mSherlock;
|
||||
|
||||
protected final ActionBarSherlock getSherlock() {
|
||||
if (mSherlock == null) {
|
||||
mSherlock = ActionBarSherlock.wrap(this, ActionBarSherlock.FLAG_DELEGATE);
|
||||
}
|
||||
return mSherlock;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Action bar and mode
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public ActionBar getSupportActionBar() {
|
||||
return getSherlock().getActionBar();
|
||||
}
|
||||
|
||||
public ActionMode startActionMode(ActionMode.Callback callback) {
|
||||
return getSherlock().startActionMode(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionModeStarted(ActionMode mode) {}
|
||||
|
||||
@Override
|
||||
public void onActionModeFinished(ActionMode mode) {}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// General lifecycle/callback dispatching
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
getSherlock().dispatchConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostResume() {
|
||||
super.onPostResume();
|
||||
getSherlock().dispatchPostResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
getSherlock().dispatchPause();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
getSherlock().dispatchStop();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
getSherlock().dispatchDestroy();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
getSherlock().dispatchPostCreate(savedInstanceState);
|
||||
super.onPostCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTitleChanged(CharSequence title, int color) {
|
||||
getSherlock().dispatchTitleChanged(title, color);
|
||||
super.onTitleChanged(title, color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onMenuOpened(int featureId, android.view.Menu menu) {
|
||||
if (getSherlock().dispatchMenuOpened(featureId, menu)) {
|
||||
return true;
|
||||
}
|
||||
return super.onMenuOpened(featureId, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPanelClosed(int featureId, android.view.Menu menu) {
|
||||
getSherlock().dispatchPanelClosed(featureId, menu);
|
||||
super.onPanelClosed(featureId, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (getSherlock().dispatchKeyEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Native menu handling
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public MenuInflater getSupportMenuInflater() {
|
||||
return getSherlock().getMenuInflater();
|
||||
}
|
||||
|
||||
public void invalidateOptionsMenu() {
|
||||
getSherlock().dispatchInvalidateOptionsMenu();
|
||||
}
|
||||
|
||||
public void supportInvalidateOptionsMenu() {
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onCreateOptionsMenu(android.view.Menu menu) {
|
||||
return getSherlock().dispatchCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onPrepareOptionsMenu(android.view.Menu menu) {
|
||||
return getSherlock().dispatchPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onOptionsItemSelected(android.view.MenuItem item) {
|
||||
return getSherlock().dispatchOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openOptionsMenu() {
|
||||
if (!getSherlock().dispatchOpenOptionsMenu()) {
|
||||
super.openOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeOptionsMenu() {
|
||||
if (!getSherlock().dispatchCloseOptionsMenu()) {
|
||||
super.closeOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Sherlock menu handling
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public boolean onCreatePanelMenu(int featureId, Menu menu) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onCreateOptionsMenu(menu);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreparePanel(int featureId, View view, Menu menu) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onPrepareOptionsMenu(menu);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onOptionsItemSelected(item);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Content
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void addContentView(View view, LayoutParams params) {
|
||||
getSherlock().addContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(int layoutResId) {
|
||||
getSherlock().setContentView(layoutResId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view, LayoutParams params) {
|
||||
getSherlock().setContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view) {
|
||||
getSherlock().setContentView(view);
|
||||
}
|
||||
|
||||
public void requestWindowFeature(long featureId) {
|
||||
getSherlock().requestFeature((int)featureId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View findViewById(int id) {
|
||||
getSherlock().ensureActionBar();
|
||||
return super.findViewById(id);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Progress Indication
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void setSupportProgress(int progress) {
|
||||
getSherlock().setProgress(progress);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarIndeterminate(boolean indeterminate) {
|
||||
getSherlock().setProgressBarIndeterminate(indeterminate);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarIndeterminateVisibility(boolean visible) {
|
||||
getSherlock().setProgressBarIndeterminateVisibility(visible);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarVisibility(boolean visible) {
|
||||
getSherlock().setProgressBarVisibility(visible);
|
||||
}
|
||||
|
||||
public void setSupportSecondaryProgress(int secondaryProgress) {
|
||||
getSherlock().setSecondaryProgress(secondaryProgress);
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
package com.actionbarsherlock.app;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.support.v4.app.Fragment;
|
||||
import com.actionbarsherlock.internal.view.menu.MenuItemWrapper;
|
||||
import com.actionbarsherlock.internal.view.menu.MenuWrapper;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
import static android.support.v4.app.Watson.OnCreateOptionsMenuListener;
|
||||
import static android.support.v4.app.Watson.OnOptionsItemSelectedListener;
|
||||
import static android.support.v4.app.Watson.OnPrepareOptionsMenuListener;
|
||||
|
||||
public class SherlockFragment extends Fragment implements OnCreateOptionsMenuListener, OnPrepareOptionsMenuListener, OnOptionsItemSelectedListener {
|
||||
private SherlockFragmentActivity mActivity;
|
||||
|
||||
public SherlockFragmentActivity getSherlockActivity() {
|
||||
return mActivity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
if (!(activity instanceof SherlockFragmentActivity)) {
|
||||
throw new IllegalStateException(getClass().getSimpleName() + " must be attached to a SherlockFragmentActivity.");
|
||||
}
|
||||
mActivity = (SherlockFragmentActivity)activity;
|
||||
|
||||
super.onAttach(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
mActivity = null;
|
||||
super.onDetach();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onCreateOptionsMenu(android.view.Menu menu, android.view.MenuInflater inflater) {
|
||||
onCreateOptionsMenu(new MenuWrapper(menu), mActivity.getSupportMenuInflater());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
//Nothing to see here.
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onPrepareOptionsMenu(android.view.Menu menu) {
|
||||
onPrepareOptionsMenu(new MenuWrapper(menu));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
//Nothing to see here.
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onOptionsItemSelected(android.view.MenuItem item) {
|
||||
return onOptionsItemSelected(new MenuItemWrapper(item));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
//Nothing to see here.
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,309 +0,0 @@
|
|||
package com.actionbarsherlock.app;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.app.Watson;
|
||||
import android.util.Log;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.view.Window;
|
||||
import com.actionbarsherlock.ActionBarSherlock;
|
||||
import com.actionbarsherlock.BuildConfig;
|
||||
import com.actionbarsherlock.view.ActionMode;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
import static com.actionbarsherlock.ActionBarSherlock.OnActionModeFinishedListener;
|
||||
import static com.actionbarsherlock.ActionBarSherlock.OnActionModeStartedListener;
|
||||
|
||||
/** @see {@link android.support.v4.app.Watson} */
|
||||
public class SherlockFragmentActivity extends Watson implements OnActionModeStartedListener, OnActionModeFinishedListener {
|
||||
private static final String TAG = "SherlockFragmentActivity";
|
||||
|
||||
private ActionBarSherlock mSherlock;
|
||||
private boolean mIgnoreNativeCreate = false;
|
||||
private boolean mIgnoreNativePrepare = false;
|
||||
private boolean mIgnoreNativeSelected = false;
|
||||
|
||||
protected final ActionBarSherlock getSherlock() {
|
||||
if (mSherlock == null) {
|
||||
mSherlock = ActionBarSherlock.wrap(this, ActionBarSherlock.FLAG_DELEGATE);
|
||||
}
|
||||
return mSherlock;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Action bar and mode
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public ActionBar getSupportActionBar() {
|
||||
return getSherlock().getActionBar();
|
||||
}
|
||||
|
||||
public ActionMode startActionMode(ActionMode.Callback callback) {
|
||||
return getSherlock().startActionMode(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionModeStarted(ActionMode mode) {}
|
||||
|
||||
@Override
|
||||
public void onActionModeFinished(ActionMode mode) {}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// General lifecycle/callback dispatching
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
getSherlock().dispatchConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostResume() {
|
||||
super.onPostResume();
|
||||
getSherlock().dispatchPostResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
getSherlock().dispatchPause();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
getSherlock().dispatchStop();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
getSherlock().dispatchDestroy();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
getSherlock().dispatchPostCreate(savedInstanceState);
|
||||
super.onPostCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTitleChanged(CharSequence title, int color) {
|
||||
getSherlock().dispatchTitleChanged(title, color);
|
||||
super.onTitleChanged(title, color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onMenuOpened(int featureId, android.view.Menu menu) {
|
||||
if (getSherlock().dispatchMenuOpened(featureId, menu)) {
|
||||
return true;
|
||||
}
|
||||
return super.onMenuOpened(featureId, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPanelClosed(int featureId, android.view.Menu menu) {
|
||||
getSherlock().dispatchPanelClosed(featureId, menu);
|
||||
super.onPanelClosed(featureId, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (getSherlock().dispatchKeyEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
getSherlock().dispatchSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
getSherlock().dispatchRestoreInstanceState(savedInstanceState);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Native menu handling
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public MenuInflater getSupportMenuInflater() {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[getSupportMenuInflater]");
|
||||
|
||||
return getSherlock().getMenuInflater();
|
||||
}
|
||||
|
||||
public void invalidateOptionsMenu() {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[invalidateOptionsMenu]");
|
||||
|
||||
getSherlock().dispatchInvalidateOptionsMenu();
|
||||
}
|
||||
|
||||
public void supportInvalidateOptionsMenu() {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[supportInvalidateOptionsMenu]");
|
||||
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onCreatePanelMenu(int featureId, android.view.Menu menu) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[onCreatePanelMenu] featureId: " + featureId + ", menu: " + menu);
|
||||
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL && !mIgnoreNativeCreate) {
|
||||
mIgnoreNativeCreate = true;
|
||||
boolean result = getSherlock().dispatchCreateOptionsMenu(menu);
|
||||
mIgnoreNativeCreate = false;
|
||||
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[onCreatePanelMenu] returning " + result);
|
||||
return result;
|
||||
}
|
||||
return super.onCreatePanelMenu(featureId, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onCreateOptionsMenu(android.view.Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onPreparePanel(int featureId, View view, android.view.Menu menu) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[onPreparePanel] featureId: " + featureId + ", view: " + view + ", menu: " + menu);
|
||||
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL && !mIgnoreNativePrepare) {
|
||||
mIgnoreNativePrepare = true;
|
||||
boolean result = getSherlock().dispatchPrepareOptionsMenu(menu);
|
||||
mIgnoreNativePrepare = false;
|
||||
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[onPreparePanel] returning " + result);
|
||||
return result;
|
||||
}
|
||||
return super.onPreparePanel(featureId, view, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onPrepareOptionsMenu(android.view.Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onMenuItemSelected(int featureId, android.view.MenuItem item) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[onMenuItemSelected] featureId: " + featureId + ", item: " + item);
|
||||
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL && !mIgnoreNativeSelected) {
|
||||
mIgnoreNativeSelected = true;
|
||||
boolean result = getSherlock().dispatchOptionsItemSelected(item);
|
||||
mIgnoreNativeSelected = false;
|
||||
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[onMenuItemSelected] returning " + result);
|
||||
return result;
|
||||
}
|
||||
return super.onMenuItemSelected(featureId, item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onOptionsItemSelected(android.view.MenuItem item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openOptionsMenu() {
|
||||
if (!getSherlock().dispatchOpenOptionsMenu()) {
|
||||
super.openOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeOptionsMenu() {
|
||||
if (!getSherlock().dispatchCloseOptionsMenu()) {
|
||||
super.closeOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Sherlock menu handling
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Content
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void addContentView(View view, LayoutParams params) {
|
||||
getSherlock().addContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(int layoutResId) {
|
||||
getSherlock().setContentView(layoutResId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view, LayoutParams params) {
|
||||
getSherlock().setContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view) {
|
||||
getSherlock().setContentView(view);
|
||||
}
|
||||
|
||||
public void requestWindowFeature(long featureId) {
|
||||
getSherlock().requestFeature((int)featureId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View findViewById(int id) {
|
||||
getSherlock().ensureActionBar();
|
||||
return super.findViewById(id);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Progress Indication
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void setSupportProgress(int progress) {
|
||||
getSherlock().setProgress(progress);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarIndeterminate(boolean indeterminate) {
|
||||
getSherlock().setProgressBarIndeterminate(indeterminate);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarIndeterminateVisibility(boolean visible) {
|
||||
getSherlock().setProgressBarIndeterminateVisibility(visible);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarVisibility(boolean visible) {
|
||||
getSherlock().setProgressBarVisibility(visible);
|
||||
}
|
||||
|
||||
public void setSupportSecondaryProgress(int secondaryProgress) {
|
||||
getSherlock().setSecondaryProgress(secondaryProgress);
|
||||
}
|
||||
}
|
|
@ -1,276 +0,0 @@
|
|||
package com.actionbarsherlock.app;
|
||||
|
||||
import android.app.ListActivity;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.Window;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import com.actionbarsherlock.ActionBarSherlock;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnActionModeFinishedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnActionModeStartedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnCreatePanelMenuListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnMenuItemSelectedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnPreparePanelListener;
|
||||
import com.actionbarsherlock.view.ActionMode;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
public abstract class SherlockListActivity extends ListActivity implements OnCreatePanelMenuListener, OnPreparePanelListener, OnMenuItemSelectedListener, OnActionModeStartedListener, OnActionModeFinishedListener {
|
||||
private ActionBarSherlock mSherlock;
|
||||
|
||||
protected final ActionBarSherlock getSherlock() {
|
||||
if (mSherlock == null) {
|
||||
mSherlock = ActionBarSherlock.wrap(this, ActionBarSherlock.FLAG_DELEGATE);
|
||||
}
|
||||
return mSherlock;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Action bar and mode
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public ActionBar getSupportActionBar() {
|
||||
return getSherlock().getActionBar();
|
||||
}
|
||||
|
||||
public ActionMode startActionMode(ActionMode.Callback callback) {
|
||||
return getSherlock().startActionMode(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionModeStarted(ActionMode mode) {}
|
||||
|
||||
@Override
|
||||
public void onActionModeFinished(ActionMode mode) {}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// General lifecycle/callback dispatching
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
getSherlock().dispatchConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostResume() {
|
||||
super.onPostResume();
|
||||
getSherlock().dispatchPostResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
getSherlock().dispatchPause();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
getSherlock().dispatchStop();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
getSherlock().dispatchDestroy();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
getSherlock().dispatchPostCreate(savedInstanceState);
|
||||
super.onPostCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTitleChanged(CharSequence title, int color) {
|
||||
getSherlock().dispatchTitleChanged(title, color);
|
||||
super.onTitleChanged(title, color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onMenuOpened(int featureId, android.view.Menu menu) {
|
||||
if (getSherlock().dispatchMenuOpened(featureId, menu)) {
|
||||
return true;
|
||||
}
|
||||
return super.onMenuOpened(featureId, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPanelClosed(int featureId, android.view.Menu menu) {
|
||||
getSherlock().dispatchPanelClosed(featureId, menu);
|
||||
super.onPanelClosed(featureId, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (getSherlock().dispatchKeyEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
getSherlock().dispatchSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
getSherlock().dispatchRestoreInstanceState(savedInstanceState);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Native menu handling
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public MenuInflater getSupportMenuInflater() {
|
||||
return getSherlock().getMenuInflater();
|
||||
}
|
||||
|
||||
public void invalidateOptionsMenu() {
|
||||
getSherlock().dispatchInvalidateOptionsMenu();
|
||||
}
|
||||
|
||||
public void supportInvalidateOptionsMenu() {
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onCreateOptionsMenu(android.view.Menu menu) {
|
||||
return getSherlock().dispatchCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onPrepareOptionsMenu(android.view.Menu menu) {
|
||||
return getSherlock().dispatchPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onOptionsItemSelected(android.view.MenuItem item) {
|
||||
return getSherlock().dispatchOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openOptionsMenu() {
|
||||
if (!getSherlock().dispatchOpenOptionsMenu()) {
|
||||
super.openOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeOptionsMenu() {
|
||||
if (!getSherlock().dispatchCloseOptionsMenu()) {
|
||||
super.closeOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Sherlock menu handling
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public boolean onCreatePanelMenu(int featureId, Menu menu) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onCreateOptionsMenu(menu);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreparePanel(int featureId, View view, Menu menu) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onPrepareOptionsMenu(menu);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onOptionsItemSelected(item);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Content
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void addContentView(View view, LayoutParams params) {
|
||||
getSherlock().addContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(int layoutResId) {
|
||||
getSherlock().setContentView(layoutResId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view, LayoutParams params) {
|
||||
getSherlock().setContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view) {
|
||||
getSherlock().setContentView(view);
|
||||
}
|
||||
|
||||
public void requestWindowFeature(long featureId) {
|
||||
getSherlock().requestFeature((int)featureId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View findViewById(int id) {
|
||||
getSherlock().ensureActionBar();
|
||||
return super.findViewById(id);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Progress Indication
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void setSupportProgress(int progress) {
|
||||
getSherlock().setProgress(progress);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarIndeterminate(boolean indeterminate) {
|
||||
getSherlock().setProgressBarIndeterminate(indeterminate);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarIndeterminateVisibility(boolean visible) {
|
||||
getSherlock().setProgressBarIndeterminateVisibility(visible);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarVisibility(boolean visible) {
|
||||
getSherlock().setProgressBarVisibility(visible);
|
||||
}
|
||||
|
||||
public void setSupportSecondaryProgress(int secondaryProgress) {
|
||||
getSherlock().setSecondaryProgress(secondaryProgress);
|
||||
}
|
||||
}
|
|
@ -1,68 +0,0 @@
|
|||
package com.actionbarsherlock.app;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.support.v4.app.ListFragment;
|
||||
import com.actionbarsherlock.internal.view.menu.MenuItemWrapper;
|
||||
import com.actionbarsherlock.internal.view.menu.MenuWrapper;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
import static android.support.v4.app.Watson.OnCreateOptionsMenuListener;
|
||||
import static android.support.v4.app.Watson.OnOptionsItemSelectedListener;
|
||||
import static android.support.v4.app.Watson.OnPrepareOptionsMenuListener;
|
||||
|
||||
public class SherlockListFragment extends ListFragment implements OnCreateOptionsMenuListener, OnPrepareOptionsMenuListener, OnOptionsItemSelectedListener {
|
||||
private SherlockFragmentActivity mActivity;
|
||||
|
||||
public SherlockFragmentActivity getSherlockActivity() {
|
||||
return mActivity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttach(Activity activity) {
|
||||
if (!(activity instanceof SherlockFragmentActivity)) {
|
||||
throw new IllegalStateException(getClass().getSimpleName() + " must be attached to a SherlockFragmentActivity.");
|
||||
}
|
||||
mActivity = (SherlockFragmentActivity)activity;
|
||||
|
||||
super.onAttach(activity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetach() {
|
||||
mActivity = null;
|
||||
super.onDetach();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onCreateOptionsMenu(android.view.Menu menu, android.view.MenuInflater inflater) {
|
||||
onCreateOptionsMenu(new MenuWrapper(menu), mActivity.getSupportMenuInflater());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
|
||||
//Nothing to see here.
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void onPrepareOptionsMenu(android.view.Menu menu) {
|
||||
onPrepareOptionsMenu(new MenuWrapper(menu));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareOptionsMenu(Menu menu) {
|
||||
//Nothing to see here.
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onOptionsItemSelected(android.view.MenuItem item) {
|
||||
return onOptionsItemSelected(new MenuItemWrapper(item));
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
//Nothing to see here.
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,276 +0,0 @@
|
|||
package com.actionbarsherlock.app;
|
||||
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Bundle;
|
||||
import android.preference.PreferenceActivity;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.view.Window;
|
||||
import com.actionbarsherlock.ActionBarSherlock;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnActionModeFinishedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnActionModeStartedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnCreatePanelMenuListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnMenuItemSelectedListener;
|
||||
import com.actionbarsherlock.ActionBarSherlock.OnPreparePanelListener;
|
||||
import com.actionbarsherlock.view.ActionMode;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
public abstract class SherlockPreferenceActivity extends PreferenceActivity implements OnCreatePanelMenuListener, OnPreparePanelListener, OnMenuItemSelectedListener, OnActionModeStartedListener, OnActionModeFinishedListener {
|
||||
private ActionBarSherlock mSherlock;
|
||||
|
||||
protected final ActionBarSherlock getSherlock() {
|
||||
if (mSherlock == null) {
|
||||
mSherlock = ActionBarSherlock.wrap(this, ActionBarSherlock.FLAG_DELEGATE);
|
||||
}
|
||||
return mSherlock;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Action bar and mode
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public ActionBar getSupportActionBar() {
|
||||
return getSherlock().getActionBar();
|
||||
}
|
||||
|
||||
public ActionMode startActionMode(ActionMode.Callback callback) {
|
||||
return getSherlock().startActionMode(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onActionModeStarted(ActionMode mode) {}
|
||||
|
||||
@Override
|
||||
public void onActionModeFinished(ActionMode mode) {}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// General lifecycle/callback dispatching
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
getSherlock().dispatchConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostResume() {
|
||||
super.onPostResume();
|
||||
getSherlock().dispatchPostResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
getSherlock().dispatchPause();
|
||||
super.onPause();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
getSherlock().dispatchStop();
|
||||
super.onStop();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
getSherlock().dispatchDestroy();
|
||||
super.onDestroy();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostCreate(Bundle savedInstanceState) {
|
||||
getSherlock().dispatchPostCreate(savedInstanceState);
|
||||
super.onPostCreate(savedInstanceState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onTitleChanged(CharSequence title, int color) {
|
||||
getSherlock().dispatchTitleChanged(title, color);
|
||||
super.onTitleChanged(title, color);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onMenuOpened(int featureId, android.view.Menu menu) {
|
||||
if (getSherlock().dispatchMenuOpened(featureId, menu)) {
|
||||
return true;
|
||||
}
|
||||
return super.onMenuOpened(featureId, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPanelClosed(int featureId, android.view.Menu menu) {
|
||||
getSherlock().dispatchPanelClosed(featureId, menu);
|
||||
super.onPanelClosed(featureId, menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchKeyEvent(KeyEvent event) {
|
||||
if (getSherlock().dispatchKeyEvent(event)) {
|
||||
return true;
|
||||
}
|
||||
return super.dispatchKeyEvent(event);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
super.onSaveInstanceState(outState);
|
||||
getSherlock().dispatchSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
getSherlock().dispatchRestoreInstanceState(savedInstanceState);
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Native menu handling
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public MenuInflater getSupportMenuInflater() {
|
||||
return getSherlock().getMenuInflater();
|
||||
}
|
||||
|
||||
public void invalidateOptionsMenu() {
|
||||
getSherlock().dispatchInvalidateOptionsMenu();
|
||||
}
|
||||
|
||||
public void supportInvalidateOptionsMenu() {
|
||||
invalidateOptionsMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onCreateOptionsMenu(android.view.Menu menu) {
|
||||
return getSherlock().dispatchCreateOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onPrepareOptionsMenu(android.view.Menu menu) {
|
||||
return getSherlock().dispatchPrepareOptionsMenu(menu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public final boolean onOptionsItemSelected(android.view.MenuItem item) {
|
||||
return getSherlock().dispatchOptionsItemSelected(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void openOptionsMenu() {
|
||||
if (!getSherlock().dispatchOpenOptionsMenu()) {
|
||||
super.openOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void closeOptionsMenu() {
|
||||
if (!getSherlock().dispatchCloseOptionsMenu()) {
|
||||
super.closeOptionsMenu();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Sherlock menu handling
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public boolean onCreatePanelMenu(int featureId, Menu menu) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onCreateOptionsMenu(menu);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onCreateOptionsMenu(Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPreparePanel(int featureId, View view, Menu menu) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onPrepareOptionsMenu(menu);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onPrepareOptionsMenu(Menu menu) {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemSelected(int featureId, MenuItem item) {
|
||||
if (featureId == Window.FEATURE_OPTIONS_PANEL) {
|
||||
return onOptionsItemSelected(item);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean onOptionsItemSelected(MenuItem item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Content
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@Override
|
||||
public void addContentView(View view, LayoutParams params) {
|
||||
getSherlock().addContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(int layoutResId) {
|
||||
getSherlock().setContentView(layoutResId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view, LayoutParams params) {
|
||||
getSherlock().setContentView(view, params);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view) {
|
||||
getSherlock().setContentView(view);
|
||||
}
|
||||
|
||||
public void requestWindowFeature(long featureId) {
|
||||
getSherlock().requestFeature((int)featureId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View findViewById(int id) {
|
||||
getSherlock().ensureActionBar();
|
||||
return super.findViewById(id);
|
||||
}
|
||||
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Progress Indication
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
|
||||
public void setSupportProgress(int progress) {
|
||||
getSherlock().setProgress(progress);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarIndeterminate(boolean indeterminate) {
|
||||
getSherlock().setProgressBarIndeterminate(indeterminate);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarIndeterminateVisibility(boolean visible) {
|
||||
getSherlock().setProgressBarIndeterminateVisibility(visible);
|
||||
}
|
||||
|
||||
public void setSupportProgressBarVisibility(boolean visible) {
|
||||
getSherlock().setProgressBarVisibility(visible);
|
||||
}
|
||||
|
||||
public void setSupportSecondaryProgress(int secondaryProgress) {
|
||||
getSherlock().setSecondaryProgress(secondaryProgress);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,352 +0,0 @@
|
|||
package com.actionbarsherlock.internal;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup.LayoutParams;
|
||||
import android.view.Window;
|
||||
import com.actionbarsherlock.ActionBarSherlock;
|
||||
import com.actionbarsherlock.BuildConfig;
|
||||
import com.actionbarsherlock.app.ActionBar;
|
||||
import com.actionbarsherlock.internal.app.ActionBarWrapper;
|
||||
import com.actionbarsherlock.internal.view.menu.MenuItemWrapper;
|
||||
import com.actionbarsherlock.internal.view.menu.MenuWrapper;
|
||||
import com.actionbarsherlock.view.ActionMode;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
@ActionBarSherlock.Implementation(api = 14)
|
||||
public class ActionBarSherlockNative extends ActionBarSherlock {
|
||||
private ActionBarWrapper mActionBar;
|
||||
private ActionModeWrapper mActionMode;
|
||||
private MenuWrapper mMenu;
|
||||
|
||||
public ActionBarSherlockNative(Activity activity, int flags) {
|
||||
super(activity, flags);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public ActionBar getActionBar() {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[getActionBar]");
|
||||
|
||||
initActionBar();
|
||||
return mActionBar;
|
||||
}
|
||||
|
||||
private void initActionBar() {
|
||||
if (mActionBar != null || mActivity.getActionBar() == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
mActionBar = new ActionBarWrapper(mActivity);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void dispatchInvalidateOptionsMenu() {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[dispatchInvalidateOptionsMenu]");
|
||||
|
||||
mActivity.getWindow().invalidatePanelMenu(Window.FEATURE_OPTIONS_PANEL);
|
||||
|
||||
if (mMenu != null) mMenu.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchCreateOptionsMenu(android.view.Menu menu) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[dispatchCreateOptionsMenu] menu: " + menu);
|
||||
|
||||
if (mMenu == null || menu != mMenu.unwrap()) {
|
||||
mMenu = new MenuWrapper(menu);
|
||||
}
|
||||
|
||||
final boolean result = callbackCreateOptionsMenu(mMenu);
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[dispatchCreateOptionsMenu] returning " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchPrepareOptionsMenu(android.view.Menu menu) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[dispatchPrepareOptionsMenu] menu: " + menu);
|
||||
|
||||
final boolean result = callbackPrepareOptionsMenu(mMenu);
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[dispatchPrepareOptionsMenu] returning " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchOptionsItemSelected(android.view.MenuItem item) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[dispatchOptionsItemSelected] item: " + item.getTitleCondensed());
|
||||
|
||||
MenuItem wrapped;
|
||||
if (mMenu == null) {
|
||||
if (item.getItemId() != android.R.id.home) {
|
||||
throw new IllegalStateException("Non-home action item clicked before onCreateOptionsMenu with ID " + item.getItemId());
|
||||
}
|
||||
// Create a throw-away wrapper for now.
|
||||
wrapped = new MenuItemWrapper(item);
|
||||
} else {
|
||||
wrapped = mMenu.findItem(item);
|
||||
}
|
||||
final boolean result = callbackOptionsItemSelected(wrapped);
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[dispatchOptionsItemSelected] returning " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFeature(int feature) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[hasFeature] feature: " + feature);
|
||||
|
||||
final boolean result = mActivity.getWindow().hasFeature(feature);
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[hasFeature] returning " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean requestFeature(int featureId) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[requestFeature] featureId: " + featureId);
|
||||
|
||||
final boolean result = mActivity.getWindow().requestFeature(featureId);
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[requestFeature] returning " + result);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUiOptions(int uiOptions) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[setUiOptions] uiOptions: " + uiOptions);
|
||||
|
||||
mActivity.getWindow().setUiOptions(uiOptions);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setUiOptions(int uiOptions, int mask) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[setUiOptions] uiOptions: " + uiOptions + ", mask: " + mask);
|
||||
|
||||
mActivity.getWindow().setUiOptions(uiOptions, mask);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(int layoutResId) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[setContentView] layoutResId: " + layoutResId);
|
||||
|
||||
mActivity.getWindow().setContentView(layoutResId);
|
||||
initActionBar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setContentView(View view, LayoutParams params) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[setContentView] view: " + view + ", params: " + params);
|
||||
|
||||
mActivity.getWindow().setContentView(view, params);
|
||||
initActionBar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addContentView(View view, LayoutParams params) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[addContentView] view: " + view + ", params: " + params);
|
||||
|
||||
mActivity.getWindow().addContentView(view, params);
|
||||
initActionBar();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(CharSequence title) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[setTitle] title: " + title);
|
||||
|
||||
mActivity.getWindow().setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgressBarVisibility(boolean visible) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[setProgressBarVisibility] visible: " + visible);
|
||||
|
||||
mActivity.setProgressBarVisibility(visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgressBarIndeterminateVisibility(boolean visible) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[setProgressBarIndeterminateVisibility] visible: " + visible);
|
||||
|
||||
mActivity.setProgressBarIndeterminateVisibility(visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgressBarIndeterminate(boolean indeterminate) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[setProgressBarIndeterminate] indeterminate: " + indeterminate);
|
||||
|
||||
mActivity.setProgressBarIndeterminate(indeterminate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProgress(int progress) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[setProgress] progress: " + progress);
|
||||
|
||||
mActivity.setProgress(progress);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSecondaryProgress(int secondaryProgress) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[setSecondaryProgress] secondaryProgress: " + secondaryProgress);
|
||||
|
||||
mActivity.setSecondaryProgress(secondaryProgress);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Context getThemedContext() {
|
||||
Context context = mActivity;
|
||||
TypedValue outValue = new TypedValue();
|
||||
mActivity.getTheme().resolveAttribute(android.R.attr.actionBarWidgetTheme, outValue, true);
|
||||
if (outValue.resourceId != 0) {
|
||||
//We are unable to test if this is the same as our current theme
|
||||
//so we just wrap it and hope that if the attribute was specified
|
||||
//then the user is intentionally specifying an alternate theme.
|
||||
context = new ContextThemeWrapper(context, outValue.resourceId);
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionMode startActionMode(com.actionbarsherlock.view.ActionMode.Callback callback) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "[startActionMode] callback: " + callback);
|
||||
|
||||
if (mActionMode != null) {
|
||||
mActionMode.finish();
|
||||
}
|
||||
ActionModeCallbackWrapper wrapped = null;
|
||||
if (callback != null) {
|
||||
wrapped = new ActionModeCallbackWrapper(callback);
|
||||
}
|
||||
|
||||
//Calling this will trigger the callback wrapper's onCreate which
|
||||
//is where we will set the new instance to mActionMode since we need
|
||||
//to pass it through to the sherlock callbacks and the call below
|
||||
//will not have returned yet to store its value.
|
||||
if (mActivity.startActionMode(wrapped) == null) {
|
||||
mActionMode = null;
|
||||
}
|
||||
if (mActivity instanceof OnActionModeStartedListener && mActionMode != null) {
|
||||
((OnActionModeStartedListener)mActivity).onActionModeStarted(mActionMode);
|
||||
}
|
||||
|
||||
return mActionMode;
|
||||
}
|
||||
|
||||
private class ActionModeCallbackWrapper implements android.view.ActionMode.Callback {
|
||||
private final ActionMode.Callback mCallback;
|
||||
|
||||
public ActionModeCallbackWrapper(ActionMode.Callback callback) {
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onCreateActionMode(android.view.ActionMode mode, android.view.Menu menu) {
|
||||
//See ActionBarSherlockNative#startActionMode
|
||||
mActionMode = new ActionModeWrapper(mode);
|
||||
|
||||
return mCallback.onCreateActionMode(mActionMode, mActionMode.getMenu());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPrepareActionMode(android.view.ActionMode mode, android.view.Menu menu) {
|
||||
return mCallback.onPrepareActionMode(mActionMode, mActionMode.getMenu());
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onActionItemClicked(android.view.ActionMode mode, android.view.MenuItem item) {
|
||||
return mCallback.onActionItemClicked(mActionMode, mActionMode.getMenu().findItem(item));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroyActionMode(android.view.ActionMode mode) {
|
||||
mCallback.onDestroyActionMode(mActionMode);
|
||||
if (mActivity instanceof OnActionModeFinishedListener) {
|
||||
((OnActionModeFinishedListener)mActivity).onActionModeFinished(mActionMode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class ActionModeWrapper extends ActionMode {
|
||||
private final android.view.ActionMode mActionMode;
|
||||
private MenuWrapper mMenu = null;
|
||||
|
||||
ActionModeWrapper(android.view.ActionMode actionMode) {
|
||||
mActionMode = actionMode;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(CharSequence title) {
|
||||
mActionMode.setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(int resId) {
|
||||
mActionMode.setTitle(resId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSubtitle(CharSequence subtitle) {
|
||||
mActionMode.setSubtitle(subtitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSubtitle(int resId) {
|
||||
mActionMode.setSubtitle(resId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomView(View view) {
|
||||
mActionMode.setCustomView(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
mActionMode.invalidate();
|
||||
if (mMenu != null) mMenu.invalidate();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
mActionMode.finish();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuWrapper getMenu() {
|
||||
if (mMenu == null) {
|
||||
mMenu = new MenuWrapper(mActionMode.getMenu());
|
||||
}
|
||||
return mMenu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTitle() {
|
||||
return mActionMode.getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSubtitle() {
|
||||
return mActionMode.getSubtitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getCustomView() {
|
||||
return mActionMode.getCustomView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuInflater getMenuInflater() {
|
||||
return ActionBarSherlockNative.this.getMenuInflater();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTag(Object tag) {
|
||||
mActionMode.setTag(tag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTag() {
|
||||
return mActionMode.getTag();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,182 +0,0 @@
|
|||
package com.actionbarsherlock.internal;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.res.AssetManager;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.os.Build;
|
||||
import android.util.DisplayMetrics;
|
||||
import android.util.Log;
|
||||
import com.actionbarsherlock.BuildConfig;
|
||||
import com.actionbarsherlock.R;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
|
||||
public final class ResourcesCompat {
|
||||
private static final String TAG = "ResourcesCompat";
|
||||
|
||||
//No instances
|
||||
private ResourcesCompat() {}
|
||||
|
||||
|
||||
/**
|
||||
* Support implementation of {@code getResources().getBoolean()} that we
|
||||
* can use to simulate filtering based on width and smallest width
|
||||
* qualifiers on pre-3.2.
|
||||
*
|
||||
* @param context Context to load booleans from on 3.2+ and to fetch the
|
||||
* display metrics.
|
||||
* @param id Id of boolean to load.
|
||||
* @return Associated boolean value as reflected by the current display
|
||||
* metrics.
|
||||
*/
|
||||
public static boolean getResources_getBoolean(Context context, int id) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
|
||||
return context.getResources().getBoolean(id);
|
||||
}
|
||||
|
||||
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
|
||||
float widthDp = metrics.widthPixels / metrics.density;
|
||||
float heightDp = metrics.heightPixels / metrics.density;
|
||||
float smallestWidthDp = (widthDp < heightDp) ? widthDp : heightDp;
|
||||
|
||||
if (id == R.bool.abs__action_bar_embed_tabs) {
|
||||
if (widthDp >= 480) {
|
||||
return true; //values-w480dp
|
||||
}
|
||||
return false; //values
|
||||
}
|
||||
if (id == R.bool.abs__split_action_bar_is_narrow) {
|
||||
if (widthDp >= 480) {
|
||||
return false; //values-w480dp
|
||||
}
|
||||
return true; //values
|
||||
}
|
||||
if (id == R.bool.abs__action_bar_expanded_action_views_exclusive) {
|
||||
if (smallestWidthDp >= 600) {
|
||||
return false; //values-sw600dp
|
||||
}
|
||||
return true; //values
|
||||
}
|
||||
if (id == R.bool.abs__config_allowActionMenuItemTextWithIcon) {
|
||||
if (widthDp >= 480) {
|
||||
return true; //values-w480dp
|
||||
}
|
||||
return false; //values
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown boolean resource ID " + id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Support implementation of {@code getResources().getInteger()} that we
|
||||
* can use to simulate filtering based on width qualifiers on pre-3.2.
|
||||
*
|
||||
* @param context Context to load integers from on 3.2+ and to fetch the
|
||||
* display metrics.
|
||||
* @param id Id of integer to load.
|
||||
* @return Associated integer value as reflected by the current display
|
||||
* metrics.
|
||||
*/
|
||||
public static int getResources_getInteger(Context context, int id) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB_MR2) {
|
||||
return context.getResources().getInteger(id);
|
||||
}
|
||||
|
||||
DisplayMetrics metrics = context.getResources().getDisplayMetrics();
|
||||
float widthDp = metrics.widthPixels / metrics.density;
|
||||
|
||||
if (id == R.integer.abs__max_action_buttons) {
|
||||
if (widthDp >= 600) {
|
||||
return 5; //values-w600dp
|
||||
}
|
||||
if (widthDp >= 500) {
|
||||
return 4; //values-w500dp
|
||||
}
|
||||
if (widthDp >= 360) {
|
||||
return 3; //values-w360dp
|
||||
}
|
||||
return 2; //values
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("Unknown integer resource ID " + id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempt to programmatically load the logo from the manifest file of an
|
||||
* activity by using an XML pull parser. This should allow us to read the
|
||||
* logo attribute regardless of the platform it is being run on.
|
||||
*
|
||||
* @param activity Activity instance.
|
||||
* @return Logo resource ID.
|
||||
*/
|
||||
public static int loadLogoFromManifest(Activity activity) {
|
||||
int logo = 0;
|
||||
try {
|
||||
final String thisPackage = activity.getClass().getName();
|
||||
if (BuildConfig.DEBUG) Log.i(TAG, "Parsing AndroidManifest.xml for " + thisPackage);
|
||||
|
||||
final String packageName = activity.getApplicationInfo().packageName;
|
||||
final AssetManager am = activity.createPackageContext(packageName, 0).getAssets();
|
||||
final XmlResourceParser xml = am.openXmlResourceParser("AndroidManifest.xml");
|
||||
|
||||
int eventType = xml.getEventType();
|
||||
while (eventType != XmlPullParser.END_DOCUMENT) {
|
||||
if (eventType == XmlPullParser.START_TAG) {
|
||||
String name = xml.getName();
|
||||
|
||||
if ("application".equals(name)) {
|
||||
//Check if the <application> has the attribute
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "Got <application>");
|
||||
|
||||
for (int i = xml.getAttributeCount() - 1; i >= 0; i--) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, xml.getAttributeName(i) + ": " + xml.getAttributeValue(i));
|
||||
|
||||
if ("logo".equals(xml.getAttributeName(i))) {
|
||||
logo = xml.getAttributeResourceValue(i, 0);
|
||||
break; //out of for loop
|
||||
}
|
||||
}
|
||||
} else if ("activity".equals(name)) {
|
||||
//Check if the <activity> is us and has the attribute
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, "Got <activity>");
|
||||
Integer activityLogo = null;
|
||||
String activityPackage = null;
|
||||
boolean isOurActivity = false;
|
||||
|
||||
for (int i = xml.getAttributeCount() - 1; i >= 0; i--) {
|
||||
if (BuildConfig.DEBUG) Log.d(TAG, xml.getAttributeName(i) + ": " + xml.getAttributeValue(i));
|
||||
|
||||
//We need both uiOptions and name attributes
|
||||
String attrName = xml.getAttributeName(i);
|
||||
if ("logo".equals(attrName)) {
|
||||
activityLogo = xml.getAttributeResourceValue(i, 0);
|
||||
} else if ("name".equals(attrName)) {
|
||||
activityPackage = ActionBarSherlockCompat.cleanActivityName(packageName, xml.getAttributeValue(i));
|
||||
if (!thisPackage.equals(activityPackage)) {
|
||||
break; //on to the next
|
||||
}
|
||||
isOurActivity = true;
|
||||
}
|
||||
|
||||
//Make sure we have both attributes before processing
|
||||
if ((activityLogo != null) && (activityPackage != null)) {
|
||||
//Our activity, logo specified, override with our value
|
||||
logo = activityLogo.intValue();
|
||||
}
|
||||
}
|
||||
if (isOurActivity) {
|
||||
//If we matched our activity but it had no logo don't
|
||||
//do any more processing of the manifest
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
eventType = xml.nextToken();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (BuildConfig.DEBUG) Log.i(TAG, "Returning " + Integer.toHexString(logo));
|
||||
return logo;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,480 +0,0 @@
|
|||
package com.actionbarsherlock.internal.app;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.support.v4.app.FragmentActivity;
|
||||
import android.support.v4.app.FragmentTransaction;
|
||||
import android.view.View;
|
||||
import android.widget.SpinnerAdapter;
|
||||
|
||||
import com.actionbarsherlock.app.ActionBar;
|
||||
|
||||
public class ActionBarWrapper extends ActionBar implements android.app.ActionBar.OnNavigationListener, android.app.ActionBar.OnMenuVisibilityListener {
|
||||
private final Activity mActivity;
|
||||
private final android.app.ActionBar mActionBar;
|
||||
private ActionBar.OnNavigationListener mNavigationListener;
|
||||
private Set<OnMenuVisibilityListener> mMenuVisibilityListeners = new HashSet<OnMenuVisibilityListener>(1);
|
||||
private FragmentTransaction mFragmentTransaction;
|
||||
|
||||
|
||||
public ActionBarWrapper(Activity activity) {
|
||||
mActivity = activity;
|
||||
mActionBar = activity.getActionBar();
|
||||
if (mActionBar != null) {
|
||||
mActionBar.addOnMenuVisibilityListener(this);
|
||||
|
||||
// Fixes issue #746
|
||||
int displayOptions = mActionBar.getDisplayOptions();
|
||||
mActionBar.setHomeButtonEnabled((displayOptions & DISPLAY_HOME_AS_UP) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void setHomeButtonEnabled(boolean enabled) {
|
||||
mActionBar.setHomeButtonEnabled(enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context getThemedContext() {
|
||||
return mActionBar.getThemedContext();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomView(View view) {
|
||||
mActionBar.setCustomView(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomView(View view, LayoutParams layoutParams) {
|
||||
android.app.ActionBar.LayoutParams lp = new android.app.ActionBar.LayoutParams(layoutParams);
|
||||
lp.gravity = layoutParams.gravity;
|
||||
lp.bottomMargin = layoutParams.bottomMargin;
|
||||
lp.topMargin = layoutParams.topMargin;
|
||||
lp.leftMargin = layoutParams.leftMargin;
|
||||
lp.rightMargin = layoutParams.rightMargin;
|
||||
mActionBar.setCustomView(view, lp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomView(int resId) {
|
||||
mActionBar.setCustomView(resId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIcon(int resId) {
|
||||
mActionBar.setIcon(resId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIcon(Drawable icon) {
|
||||
mActionBar.setIcon(icon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLogo(int resId) {
|
||||
mActionBar.setLogo(resId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setLogo(Drawable logo) {
|
||||
mActionBar.setLogo(logo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
|
||||
mNavigationListener = callback;
|
||||
mActionBar.setListNavigationCallbacks(adapter, (callback != null) ? this : null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onNavigationItemSelected(int itemPosition, long itemId) {
|
||||
//This should never be a NullPointerException since we only set
|
||||
//ourselves as the listener when the callback is not null.
|
||||
return mNavigationListener.onNavigationItemSelected(itemPosition, itemId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelectedNavigationItem(int position) {
|
||||
mActionBar.setSelectedNavigationItem(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getSelectedNavigationIndex() {
|
||||
return mActionBar.getSelectedNavigationIndex();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNavigationItemCount() {
|
||||
return mActionBar.getNavigationItemCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(CharSequence title) {
|
||||
mActionBar.setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(int resId) {
|
||||
mActionBar.setTitle(resId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSubtitle(CharSequence subtitle) {
|
||||
mActionBar.setSubtitle(subtitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSubtitle(int resId) {
|
||||
mActionBar.setSubtitle(resId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayOptions(int options) {
|
||||
mActionBar.setDisplayOptions(options);
|
||||
|
||||
// Fixes issue #746
|
||||
mActionBar.setHomeButtonEnabled((options & DISPLAY_HOME_AS_UP) != 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayOptions(int options, int mask) {
|
||||
mActionBar.setDisplayOptions(options, mask);
|
||||
|
||||
// Fixes issue #746
|
||||
if ((mask & DISPLAY_HOME_AS_UP) != 0) {
|
||||
mActionBar.setHomeButtonEnabled((options & DISPLAY_HOME_AS_UP) != 0);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayUseLogoEnabled(boolean useLogo) {
|
||||
mActionBar.setDisplayUseLogoEnabled(useLogo);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayShowHomeEnabled(boolean showHome) {
|
||||
mActionBar.setDisplayShowHomeEnabled(showHome);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) {
|
||||
mActionBar.setDisplayHomeAsUpEnabled(showHomeAsUp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayShowTitleEnabled(boolean showTitle) {
|
||||
mActionBar.setDisplayShowTitleEnabled(showTitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setDisplayShowCustomEnabled(boolean showCustom) {
|
||||
mActionBar.setDisplayShowCustomEnabled(showCustom);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setBackgroundDrawable(Drawable d) {
|
||||
mActionBar.setBackgroundDrawable(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setStackedBackgroundDrawable(Drawable d) {
|
||||
mActionBar.setStackedBackgroundDrawable(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSplitBackgroundDrawable(Drawable d) {
|
||||
mActionBar.setSplitBackgroundDrawable(d);
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getCustomView() {
|
||||
return mActionBar.getCustomView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTitle() {
|
||||
return mActionBar.getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSubtitle() {
|
||||
return mActionBar.getSubtitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getNavigationMode() {
|
||||
return mActionBar.getNavigationMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNavigationMode(int mode) {
|
||||
mActionBar.setNavigationMode(mode);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getDisplayOptions() {
|
||||
return mActionBar.getDisplayOptions();
|
||||
}
|
||||
|
||||
public class TabWrapper extends ActionBar.Tab implements android.app.ActionBar.TabListener {
|
||||
final android.app.ActionBar.Tab mNativeTab;
|
||||
private Object mTag;
|
||||
private TabListener mListener;
|
||||
|
||||
public TabWrapper(android.app.ActionBar.Tab nativeTab) {
|
||||
mNativeTab = nativeTab;
|
||||
mNativeTab.setTag(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPosition() {
|
||||
return mNativeTab.getPosition();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getIcon() {
|
||||
return mNativeTab.getIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getText() {
|
||||
return mNativeTab.getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab setIcon(Drawable icon) {
|
||||
mNativeTab.setIcon(icon);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab setIcon(int resId) {
|
||||
mNativeTab.setIcon(resId);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab setText(CharSequence text) {
|
||||
mNativeTab.setText(text);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab setText(int resId) {
|
||||
mNativeTab.setText(resId);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab setCustomView(View view) {
|
||||
mNativeTab.setCustomView(view);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab setCustomView(int layoutResId) {
|
||||
mNativeTab.setCustomView(layoutResId);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getCustomView() {
|
||||
return mNativeTab.getCustomView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab setTag(Object obj) {
|
||||
mTag = obj;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getTag() {
|
||||
return mTag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab setTabListener(TabListener listener) {
|
||||
mNativeTab.setTabListener(listener != null ? this : null);
|
||||
mListener = listener;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void select() {
|
||||
mNativeTab.select();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab setContentDescription(int resId) {
|
||||
mNativeTab.setContentDescription(resId);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab setContentDescription(CharSequence contentDesc) {
|
||||
mNativeTab.setContentDescription(contentDesc);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getContentDescription() {
|
||||
return mNativeTab.getContentDescription();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabReselected(android.app.ActionBar.Tab tab, android.app.FragmentTransaction ft) {
|
||||
if (mListener != null) {
|
||||
FragmentTransaction trans = null;
|
||||
if (mActivity instanceof FragmentActivity) {
|
||||
trans = ((FragmentActivity)mActivity).getSupportFragmentManager().beginTransaction()
|
||||
.disallowAddToBackStack();
|
||||
}
|
||||
|
||||
mListener.onTabReselected(this, trans);
|
||||
|
||||
if (trans != null && !trans.isEmpty()) {
|
||||
trans.commit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabSelected(android.app.ActionBar.Tab tab, android.app.FragmentTransaction ft) {
|
||||
if (mListener != null) {
|
||||
|
||||
if (mFragmentTransaction == null && mActivity instanceof FragmentActivity) {
|
||||
mFragmentTransaction = ((FragmentActivity)mActivity).getSupportFragmentManager().beginTransaction()
|
||||
.disallowAddToBackStack();
|
||||
}
|
||||
|
||||
mListener.onTabSelected(this, mFragmentTransaction);
|
||||
|
||||
if (mFragmentTransaction != null) {
|
||||
if (!mFragmentTransaction.isEmpty()) {
|
||||
mFragmentTransaction.commit();
|
||||
}
|
||||
mFragmentTransaction = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTabUnselected(android.app.ActionBar.Tab tab, android.app.FragmentTransaction ft) {
|
||||
if (mListener != null) {
|
||||
FragmentTransaction trans = null;
|
||||
if (mActivity instanceof FragmentActivity) {
|
||||
trans = ((FragmentActivity)mActivity).getSupportFragmentManager().beginTransaction()
|
||||
.disallowAddToBackStack();
|
||||
mFragmentTransaction = trans;
|
||||
}
|
||||
|
||||
mListener.onTabUnselected(this, trans);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab newTab() {
|
||||
return new TabWrapper(mActionBar.newTab());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTab(Tab tab) {
|
||||
mActionBar.addTab(((TabWrapper)tab).mNativeTab);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTab(Tab tab, boolean setSelected) {
|
||||
mActionBar.addTab(((TabWrapper)tab).mNativeTab, setSelected);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTab(Tab tab, int position) {
|
||||
mActionBar.addTab(((TabWrapper)tab).mNativeTab, position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addTab(Tab tab, int position, boolean setSelected) {
|
||||
mActionBar.addTab(((TabWrapper)tab).mNativeTab, position, setSelected);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTab(Tab tab) {
|
||||
mActionBar.removeTab(((TabWrapper)tab).mNativeTab);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeTabAt(int position) {
|
||||
mActionBar.removeTabAt(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeAllTabs() {
|
||||
mActionBar.removeAllTabs();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void selectTab(Tab tab) {
|
||||
mActionBar.selectTab(((TabWrapper)tab).mNativeTab);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getSelectedTab() {
|
||||
android.app.ActionBar.Tab selected = mActionBar.getSelectedTab();
|
||||
return (selected != null) ? (Tab)selected.getTag() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Tab getTabAt(int index) {
|
||||
android.app.ActionBar.Tab selected = mActionBar.getTabAt(index);
|
||||
return (selected != null) ? (Tab)selected.getTag() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTabCount() {
|
||||
return mActionBar.getTabCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getHeight() {
|
||||
return mActionBar.getHeight();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
mActionBar.show();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void hide() {
|
||||
mActionBar.hide();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShowing() {
|
||||
return mActionBar.isShowing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
|
||||
mMenuVisibilityListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
|
||||
mMenuVisibilityListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMenuVisibilityChanged(boolean isVisible) {
|
||||
for (OnMenuVisibilityListener listener : mMenuVisibilityListeners) {
|
||||
listener.onMenuVisibilityChanged(isVisible);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,278 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.nineoldandroids.animation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
/**
|
||||
* This is the superclass for classes which provide basic support for animations which can be
|
||||
* started, ended, and have <code>AnimatorListeners</code> added to them.
|
||||
*/
|
||||
public abstract class Animator implements Cloneable {
|
||||
|
||||
|
||||
/**
|
||||
* The set of listeners to be sent events through the life of an animation.
|
||||
*/
|
||||
ArrayList<AnimatorListener> mListeners = null;
|
||||
|
||||
/**
|
||||
* Starts this animation. If the animation has a nonzero startDelay, the animation will start
|
||||
* running after that delay elapses. A non-delayed animation will have its initial
|
||||
* value(s) set immediately, followed by calls to
|
||||
* {@link AnimatorListener#onAnimationStart(Animator)} for any listeners of this animator.
|
||||
*
|
||||
* <p>The animation started by calling this method will be run on the thread that called
|
||||
* this method. This thread should have a Looper on it (a runtime exception will be thrown if
|
||||
* this is not the case). Also, if the animation will animate
|
||||
* properties of objects in the view hierarchy, then the calling thread should be the UI
|
||||
* thread for that view hierarchy.</p>
|
||||
*
|
||||
*/
|
||||
public void start() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels the animation. Unlike {@link #end()}, <code>cancel()</code> causes the animation to
|
||||
* stop in its tracks, sending an
|
||||
* {@link android.animation.Animator.AnimatorListener#onAnimationCancel(Animator)} to
|
||||
* its listeners, followed by an
|
||||
* {@link android.animation.Animator.AnimatorListener#onAnimationEnd(Animator)} message.
|
||||
*
|
||||
* <p>This method must be called on the thread that is running the animation.</p>
|
||||
*/
|
||||
public void cancel() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Ends the animation. This causes the animation to assign the end value of the property being
|
||||
* animated, then calling the
|
||||
* {@link android.animation.Animator.AnimatorListener#onAnimationEnd(Animator)} method on
|
||||
* its listeners.
|
||||
*
|
||||
* <p>This method must be called on the thread that is running the animation.</p>
|
||||
*/
|
||||
public void end() {
|
||||
}
|
||||
|
||||
/**
|
||||
* The amount of time, in milliseconds, to delay starting the animation after
|
||||
* {@link #start()} is called.
|
||||
*
|
||||
* @return the number of milliseconds to delay running the animation
|
||||
*/
|
||||
public abstract long getStartDelay();
|
||||
|
||||
/**
|
||||
* The amount of time, in milliseconds, to delay starting the animation after
|
||||
* {@link #start()} is called.
|
||||
|
||||
* @param startDelay The amount of the delay, in milliseconds
|
||||
*/
|
||||
public abstract void setStartDelay(long startDelay);
|
||||
|
||||
|
||||
/**
|
||||
* Sets the length of the animation.
|
||||
*
|
||||
* @param duration The length of the animation, in milliseconds.
|
||||
*/
|
||||
public abstract Animator setDuration(long duration);
|
||||
|
||||
/**
|
||||
* Gets the length of the animation.
|
||||
*
|
||||
* @return The length of the animation, in milliseconds.
|
||||
*/
|
||||
public abstract long getDuration();
|
||||
|
||||
/**
|
||||
* The time interpolator used in calculating the elapsed fraction of this animation. The
|
||||
* interpolator determines whether the animation runs with linear or non-linear motion,
|
||||
* such as acceleration and deceleration. The default value is
|
||||
* {@link android.view.animation.AccelerateDecelerateInterpolator}
|
||||
*
|
||||
* @param value the interpolator to be used by this animation
|
||||
*/
|
||||
public abstract void setInterpolator(/*Time*/Interpolator value);
|
||||
|
||||
/**
|
||||
* Returns whether this Animator is currently running (having been started and gone past any
|
||||
* initial startDelay period and not yet ended).
|
||||
*
|
||||
* @return Whether the Animator is running.
|
||||
*/
|
||||
public abstract boolean isRunning();
|
||||
|
||||
/**
|
||||
* Returns whether this Animator has been started and not yet ended. This state is a superset
|
||||
* of the state of {@link #isRunning()}, because an Animator with a nonzero
|
||||
* {@link #getStartDelay() startDelay} will return true for {@link #isStarted()} during the
|
||||
* delay phase, whereas {@link #isRunning()} will return true only after the delay phase
|
||||
* is complete.
|
||||
*
|
||||
* @return Whether the Animator has been started and not yet ended.
|
||||
*/
|
||||
public boolean isStarted() {
|
||||
// Default method returns value for isRunning(). Subclasses should override to return a
|
||||
// real value.
|
||||
return isRunning();
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a listener to the set of listeners that are sent events through the life of an
|
||||
* animation, such as start, repeat, and end.
|
||||
*
|
||||
* @param listener the listener to be added to the current set of listeners for this animation.
|
||||
*/
|
||||
public void addListener(AnimatorListener listener) {
|
||||
if (mListeners == null) {
|
||||
mListeners = new ArrayList<AnimatorListener>();
|
||||
}
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a listener from the set listening to this animation.
|
||||
*
|
||||
* @param listener the listener to be removed from the current set of listeners for this
|
||||
* animation.
|
||||
*/
|
||||
public void removeListener(AnimatorListener listener) {
|
||||
if (mListeners == null) {
|
||||
return;
|
||||
}
|
||||
mListeners.remove(listener);
|
||||
if (mListeners.size() == 0) {
|
||||
mListeners = null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of {@link android.animation.Animator.AnimatorListener} objects that are currently
|
||||
* listening for events on this <code>Animator</code> object.
|
||||
*
|
||||
* @return ArrayList<AnimatorListener> The set of listeners.
|
||||
*/
|
||||
public ArrayList<AnimatorListener> getListeners() {
|
||||
return mListeners;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes all listeners from this object. This is equivalent to calling
|
||||
* <code>getListeners()</code> followed by calling <code>clear()</code> on the
|
||||
* returned list of listeners.
|
||||
*/
|
||||
public void removeAllListeners() {
|
||||
if (mListeners != null) {
|
||||
mListeners.clear();
|
||||
mListeners = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Animator clone() {
|
||||
try {
|
||||
final Animator anim = (Animator) super.clone();
|
||||
if (mListeners != null) {
|
||||
ArrayList<AnimatorListener> oldListeners = mListeners;
|
||||
anim.mListeners = new ArrayList<AnimatorListener>();
|
||||
int numListeners = oldListeners.size();
|
||||
for (int i = 0; i < numListeners; ++i) {
|
||||
anim.mListeners.add(oldListeners.get(i));
|
||||
}
|
||||
}
|
||||
return anim;
|
||||
} catch (CloneNotSupportedException e) {
|
||||
throw new AssertionError();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method tells the object to use appropriate information to extract
|
||||
* starting values for the animation. For example, a AnimatorSet object will pass
|
||||
* this call to its child objects to tell them to set up the values. A
|
||||
* ObjectAnimator object will use the information it has about its target object
|
||||
* and PropertyValuesHolder objects to get the start values for its properties.
|
||||
* An ValueAnimator object will ignore the request since it does not have enough
|
||||
* information (such as a target object) to gather these values.
|
||||
*/
|
||||
public void setupStartValues() {
|
||||
}
|
||||
|
||||
/**
|
||||
* This method tells the object to use appropriate information to extract
|
||||
* ending values for the animation. For example, a AnimatorSet object will pass
|
||||
* this call to its child objects to tell them to set up the values. A
|
||||
* ObjectAnimator object will use the information it has about its target object
|
||||
* and PropertyValuesHolder objects to get the start values for its properties.
|
||||
* An ValueAnimator object will ignore the request since it does not have enough
|
||||
* information (such as a target object) to gather these values.
|
||||
*/
|
||||
public void setupEndValues() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the target object whose property will be animated by this animation. Not all subclasses
|
||||
* operate on target objects (for example, {@link ValueAnimator}, but this method
|
||||
* is on the superclass for the convenience of dealing generically with those subclasses
|
||||
* that do handle targets.
|
||||
*
|
||||
* @param target The object being animated
|
||||
*/
|
||||
public void setTarget(Object target) {
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>An animation listener receives notifications from an animation.
|
||||
* Notifications indicate animation related events, such as the end or the
|
||||
* repetition of the animation.</p>
|
||||
*/
|
||||
public static interface AnimatorListener {
|
||||
/**
|
||||
* <p>Notifies the start of the animation.</p>
|
||||
*
|
||||
* @param animation The started animation.
|
||||
*/
|
||||
void onAnimationStart(Animator animation);
|
||||
|
||||
/**
|
||||
* <p>Notifies the end of the animation. This callback is not invoked
|
||||
* for animations with repeat count set to INFINITE.</p>
|
||||
*
|
||||
* @param animation The animation which reached its end.
|
||||
*/
|
||||
void onAnimationEnd(Animator animation);
|
||||
|
||||
/**
|
||||
* <p>Notifies the cancellation of the animation. This callback is not invoked
|
||||
* for animations with repeat count set to INFINITE.</p>
|
||||
*
|
||||
* @param animation The animation which was canceled.
|
||||
*/
|
||||
void onAnimationCancel(Animator animation);
|
||||
|
||||
/**
|
||||
* <p>Notifies the repetition of the animation.</p>
|
||||
*
|
||||
* @param animation The animation which was repeated.
|
||||
*/
|
||||
void onAnimationRepeat(Animator animation);
|
||||
}
|
||||
}
|
|
@ -1,54 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.nineoldandroids.animation;
|
||||
|
||||
/**
|
||||
* This adapter class provides empty implementations of the methods from {@link android.animation.Animator.AnimatorListener}.
|
||||
* Any custom listener that cares only about a subset of the methods of this listener can
|
||||
* simply subclass this adapter class instead of implementing the interface directly.
|
||||
*/
|
||||
public abstract class AnimatorListenerAdapter implements Animator.AnimatorListener {
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritDoc}
|
||||
*/
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
}
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.nineoldandroids.animation;
|
||||
|
||||
/**
|
||||
* This evaluator can be used to perform type interpolation between <code>float</code> values.
|
||||
*/
|
||||
public class FloatEvaluator implements TypeEvaluator<Number> {
|
||||
|
||||
/**
|
||||
* This function returns the result of linearly interpolating the start and end values, with
|
||||
* <code>fraction</code> representing the proportion between the start and end values. The
|
||||
* calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
|
||||
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
|
||||
* and <code>t</code> is <code>fraction</code>.
|
||||
*
|
||||
* @param fraction The fraction from the starting to the ending values
|
||||
* @param startValue The start value; should be of type <code>float</code> or
|
||||
* <code>Float</code>
|
||||
* @param endValue The end value; should be of type <code>float</code> or <code>Float</code>
|
||||
* @return A linear interpolation between the start and end values, given the
|
||||
* <code>fraction</code> parameter.
|
||||
*/
|
||||
public Float evaluate(float fraction, Number startValue, Number endValue) {
|
||||
float startFloat = startValue.floatValue();
|
||||
return startFloat + fraction * (endValue.floatValue() - startFloat);
|
||||
}
|
||||
}
|
|
@ -1,135 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.nineoldandroids.animation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.Keyframe.FloatKeyframe;
|
||||
|
||||
/**
|
||||
* This class holds a collection of FloatKeyframe objects and is called by ValueAnimator to calculate
|
||||
* values between those keyframes for a given animation. The class internal to the animation
|
||||
* package because it is an implementation detail of how Keyframes are stored and used.
|
||||
*
|
||||
* <p>This type-specific subclass of KeyframeSet, along with the other type-specific subclass for
|
||||
* int, exists to speed up the getValue() method when there is no custom
|
||||
* TypeEvaluator set for the animation, so that values can be calculated without autoboxing to the
|
||||
* Object equivalents of these primitive types.</p>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
class FloatKeyframeSet extends KeyframeSet {
|
||||
private float firstValue;
|
||||
private float lastValue;
|
||||
private float deltaValue;
|
||||
private boolean firstTime = true;
|
||||
|
||||
public FloatKeyframeSet(FloatKeyframe... keyframes) {
|
||||
super(keyframes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(float fraction) {
|
||||
return getFloatValue(fraction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatKeyframeSet clone() {
|
||||
ArrayList<Keyframe> keyframes = mKeyframes;
|
||||
int numKeyframes = mKeyframes.size();
|
||||
FloatKeyframe[] newKeyframes = new FloatKeyframe[numKeyframes];
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
newKeyframes[i] = (FloatKeyframe) keyframes.get(i).clone();
|
||||
}
|
||||
FloatKeyframeSet newSet = new FloatKeyframeSet(newKeyframes);
|
||||
return newSet;
|
||||
}
|
||||
|
||||
public float getFloatValue(float fraction) {
|
||||
if (mNumKeyframes == 2) {
|
||||
if (firstTime) {
|
||||
firstTime = false;
|
||||
firstValue = ((FloatKeyframe) mKeyframes.get(0)).getFloatValue();
|
||||
lastValue = ((FloatKeyframe) mKeyframes.get(1)).getFloatValue();
|
||||
deltaValue = lastValue - firstValue;
|
||||
}
|
||||
if (mInterpolator != null) {
|
||||
fraction = mInterpolator.getInterpolation(fraction);
|
||||
}
|
||||
if (mEvaluator == null) {
|
||||
return firstValue + fraction * deltaValue;
|
||||
} else {
|
||||
return ((Number)mEvaluator.evaluate(fraction, firstValue, lastValue)).floatValue();
|
||||
}
|
||||
}
|
||||
if (fraction <= 0f) {
|
||||
final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0);
|
||||
final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(1);
|
||||
float prevValue = prevKeyframe.getFloatValue();
|
||||
float nextValue = nextKeyframe.getFloatValue();
|
||||
float prevFraction = prevKeyframe.getFraction();
|
||||
float nextFraction = nextKeyframe.getFraction();
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
|
||||
return mEvaluator == null ?
|
||||
prevValue + intervalFraction * (nextValue - prevValue) :
|
||||
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
|
||||
floatValue();
|
||||
} else if (fraction >= 1f) {
|
||||
final FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 2);
|
||||
final FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(mNumKeyframes - 1);
|
||||
float prevValue = prevKeyframe.getFloatValue();
|
||||
float nextValue = nextKeyframe.getFloatValue();
|
||||
float prevFraction = prevKeyframe.getFraction();
|
||||
float nextFraction = nextKeyframe.getFraction();
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
|
||||
return mEvaluator == null ?
|
||||
prevValue + intervalFraction * (nextValue - prevValue) :
|
||||
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
|
||||
floatValue();
|
||||
}
|
||||
FloatKeyframe prevKeyframe = (FloatKeyframe) mKeyframes.get(0);
|
||||
for (int i = 1; i < mNumKeyframes; ++i) {
|
||||
FloatKeyframe nextKeyframe = (FloatKeyframe) mKeyframes.get(i);
|
||||
if (fraction < nextKeyframe.getFraction()) {
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevKeyframe.getFraction()) /
|
||||
(nextKeyframe.getFraction() - prevKeyframe.getFraction());
|
||||
float prevValue = prevKeyframe.getFloatValue();
|
||||
float nextValue = nextKeyframe.getFloatValue();
|
||||
return mEvaluator == null ?
|
||||
prevValue + intervalFraction * (nextValue - prevValue) :
|
||||
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
|
||||
floatValue();
|
||||
}
|
||||
prevKeyframe = nextKeyframe;
|
||||
}
|
||||
// shouldn't get here
|
||||
return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).floatValue();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,42 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.nineoldandroids.animation;
|
||||
|
||||
/**
|
||||
* This evaluator can be used to perform type interpolation between <code>int</code> values.
|
||||
*/
|
||||
public class IntEvaluator implements TypeEvaluator<Integer> {
|
||||
|
||||
/**
|
||||
* This function returns the result of linearly interpolating the start and end values, with
|
||||
* <code>fraction</code> representing the proportion between the start and end values. The
|
||||
* calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
|
||||
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
|
||||
* and <code>t</code> is <code>fraction</code>.
|
||||
*
|
||||
* @param fraction The fraction from the starting to the ending values
|
||||
* @param startValue The start value; should be of type <code>int</code> or
|
||||
* <code>Integer</code>
|
||||
* @param endValue The end value; should be of type <code>int</code> or <code>Integer</code>
|
||||
* @return A linear interpolation between the start and end values, given the
|
||||
* <code>fraction</code> parameter.
|
||||
*/
|
||||
public Integer evaluate(float fraction, Integer startValue, Integer endValue) {
|
||||
int startInt = startValue;
|
||||
return (int)(startInt + fraction * (endValue - startInt));
|
||||
}
|
||||
}
|
|
@ -1,134 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.nineoldandroids.animation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.Keyframe.IntKeyframe;
|
||||
|
||||
/**
|
||||
* This class holds a collection of IntKeyframe objects and is called by ValueAnimator to calculate
|
||||
* values between those keyframes for a given animation. The class internal to the animation
|
||||
* package because it is an implementation detail of how Keyframes are stored and used.
|
||||
*
|
||||
* <p>This type-specific subclass of KeyframeSet, along with the other type-specific subclass for
|
||||
* float, exists to speed up the getValue() method when there is no custom
|
||||
* TypeEvaluator set for the animation, so that values can be calculated without autoboxing to the
|
||||
* Object equivalents of these primitive types.</p>
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
class IntKeyframeSet extends KeyframeSet {
|
||||
private int firstValue;
|
||||
private int lastValue;
|
||||
private int deltaValue;
|
||||
private boolean firstTime = true;
|
||||
|
||||
public IntKeyframeSet(IntKeyframe... keyframes) {
|
||||
super(keyframes);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getValue(float fraction) {
|
||||
return getIntValue(fraction);
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntKeyframeSet clone() {
|
||||
ArrayList<Keyframe> keyframes = mKeyframes;
|
||||
int numKeyframes = mKeyframes.size();
|
||||
IntKeyframe[] newKeyframes = new IntKeyframe[numKeyframes];
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
newKeyframes[i] = (IntKeyframe) keyframes.get(i).clone();
|
||||
}
|
||||
IntKeyframeSet newSet = new IntKeyframeSet(newKeyframes);
|
||||
return newSet;
|
||||
}
|
||||
|
||||
public int getIntValue(float fraction) {
|
||||
if (mNumKeyframes == 2) {
|
||||
if (firstTime) {
|
||||
firstTime = false;
|
||||
firstValue = ((IntKeyframe) mKeyframes.get(0)).getIntValue();
|
||||
lastValue = ((IntKeyframe) mKeyframes.get(1)).getIntValue();
|
||||
deltaValue = lastValue - firstValue;
|
||||
}
|
||||
if (mInterpolator != null) {
|
||||
fraction = mInterpolator.getInterpolation(fraction);
|
||||
}
|
||||
if (mEvaluator == null) {
|
||||
return firstValue + (int)(fraction * deltaValue);
|
||||
} else {
|
||||
return ((Number)mEvaluator.evaluate(fraction, firstValue, lastValue)).intValue();
|
||||
}
|
||||
}
|
||||
if (fraction <= 0f) {
|
||||
final IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(0);
|
||||
final IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(1);
|
||||
int prevValue = prevKeyframe.getIntValue();
|
||||
int nextValue = nextKeyframe.getIntValue();
|
||||
float prevFraction = prevKeyframe.getFraction();
|
||||
float nextFraction = nextKeyframe.getFraction();
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
|
||||
return mEvaluator == null ?
|
||||
prevValue + (int)(intervalFraction * (nextValue - prevValue)) :
|
||||
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
|
||||
intValue();
|
||||
} else if (fraction >= 1f) {
|
||||
final IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(mNumKeyframes - 2);
|
||||
final IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(mNumKeyframes - 1);
|
||||
int prevValue = prevKeyframe.getIntValue();
|
||||
int nextValue = nextKeyframe.getIntValue();
|
||||
float prevFraction = prevKeyframe.getFraction();
|
||||
float nextFraction = nextKeyframe.getFraction();
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevFraction) / (nextFraction - prevFraction);
|
||||
return mEvaluator == null ?
|
||||
prevValue + (int)(intervalFraction * (nextValue - prevValue)) :
|
||||
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).intValue();
|
||||
}
|
||||
IntKeyframe prevKeyframe = (IntKeyframe) mKeyframes.get(0);
|
||||
for (int i = 1; i < mNumKeyframes; ++i) {
|
||||
IntKeyframe nextKeyframe = (IntKeyframe) mKeyframes.get(i);
|
||||
if (fraction < nextKeyframe.getFraction()) {
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
float intervalFraction = (fraction - prevKeyframe.getFraction()) /
|
||||
(nextKeyframe.getFraction() - prevKeyframe.getFraction());
|
||||
int prevValue = prevKeyframe.getIntValue();
|
||||
int nextValue = nextKeyframe.getIntValue();
|
||||
return mEvaluator == null ?
|
||||
prevValue + (int)(intervalFraction * (nextValue - prevValue)) :
|
||||
((Number)mEvaluator.evaluate(intervalFraction, prevValue, nextValue)).
|
||||
intValue();
|
||||
}
|
||||
prevKeyframe = nextKeyframe;
|
||||
}
|
||||
// shouldn't get here
|
||||
return ((Number)mKeyframes.get(mNumKeyframes - 1).getValue()).intValue();
|
||||
}
|
||||
|
||||
}
|
|
@ -1,361 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.nineoldandroids.animation;
|
||||
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
/**
|
||||
* This class holds a time/value pair for an animation. The Keyframe class is used
|
||||
* by {@link ValueAnimator} to define the values that the animation target will have over the course
|
||||
* of the animation. As the time proceeds from one keyframe to the other, the value of the
|
||||
* target object will animate between the value at the previous keyframe and the value at the
|
||||
* next keyframe. Each keyframe also holds an optional {@link TimeInterpolator}
|
||||
* object, which defines the time interpolation over the intervalue preceding the keyframe.
|
||||
*
|
||||
* <p>The Keyframe class itself is abstract. The type-specific factory methods will return
|
||||
* a subclass of Keyframe specific to the type of value being stored. This is done to improve
|
||||
* performance when dealing with the most common cases (e.g., <code>float</code> and
|
||||
* <code>int</code> values). Other types will fall into a more general Keyframe class that
|
||||
* treats its values as Objects. Unless your animation requires dealing with a custom type
|
||||
* or a data structure that needs to be animated directly (and evaluated using an implementation
|
||||
* of {@link TypeEvaluator}), you should stick to using float and int as animations using those
|
||||
* types have lower runtime overhead than other types.</p>
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public abstract class Keyframe implements Cloneable {
|
||||
/**
|
||||
* The time at which mValue will hold true.
|
||||
*/
|
||||
float mFraction;
|
||||
|
||||
/**
|
||||
* The type of the value in this Keyframe. This type is determined at construction time,
|
||||
* based on the type of the <code>value</code> object passed into the constructor.
|
||||
*/
|
||||
Class mValueType;
|
||||
|
||||
/**
|
||||
* The optional time interpolator for the interval preceding this keyframe. A null interpolator
|
||||
* (the default) results in linear interpolation over the interval.
|
||||
*/
|
||||
private /*Time*/Interpolator mInterpolator = null;
|
||||
|
||||
/**
|
||||
* Flag to indicate whether this keyframe has a valid value. This flag is used when an
|
||||
* animation first starts, to populate placeholder keyframes with real values derived
|
||||
* from the target object.
|
||||
*/
|
||||
boolean mHasValue = false;
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time and value. The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
* @param value The value that the object will animate to as the animation time approaches
|
||||
* the time in this keyframe, and the the value animated from as the time passes the time in
|
||||
* this keyframe.
|
||||
*/
|
||||
public static Keyframe ofInt(float fraction, int value) {
|
||||
return new IntKeyframe(fraction, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time. The value at this time will be derived
|
||||
* from the target object when the animation first starts (note that this implies that keyframes
|
||||
* with no initial value must be used as part of an {@link ObjectAnimator}).
|
||||
* The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
*/
|
||||
public static Keyframe ofInt(float fraction) {
|
||||
return new IntKeyframe(fraction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time and value. The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
* @param value The value that the object will animate to as the animation time approaches
|
||||
* the time in this keyframe, and the the value animated from as the time passes the time in
|
||||
* this keyframe.
|
||||
*/
|
||||
public static Keyframe ofFloat(float fraction, float value) {
|
||||
return new FloatKeyframe(fraction, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time. The value at this time will be derived
|
||||
* from the target object when the animation first starts (note that this implies that keyframes
|
||||
* with no initial value must be used as part of an {@link ObjectAnimator}).
|
||||
* The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
*/
|
||||
public static Keyframe ofFloat(float fraction) {
|
||||
return new FloatKeyframe(fraction);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time and value. The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
* @param value The value that the object will animate to as the animation time approaches
|
||||
* the time in this keyframe, and the the value animated from as the time passes the time in
|
||||
* this keyframe.
|
||||
*/
|
||||
public static Keyframe ofObject(float fraction, Object value) {
|
||||
return new ObjectKeyframe(fraction, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a Keyframe object with the given time. The value at this time will be derived
|
||||
* from the target object when the animation first starts (note that this implies that keyframes
|
||||
* with no initial value must be used as part of an {@link ObjectAnimator}).
|
||||
* The time defines the
|
||||
* time, as a proportion of an overall animation's duration, at which the value will hold true
|
||||
* for the animation. The value for the animation between keyframes will be calculated as
|
||||
* an interpolation between the values at those keyframes.
|
||||
*
|
||||
* @param fraction The time, expressed as a value between 0 and 1, representing the fraction
|
||||
* of time elapsed of the overall animation duration.
|
||||
*/
|
||||
public static Keyframe ofObject(float fraction) {
|
||||
return new ObjectKeyframe(fraction, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this keyframe has a valid value. This method is called internally when
|
||||
* an {@link ObjectAnimator} first starts; keyframes without values are assigned values at
|
||||
* that time by deriving the value for the property from the target object.
|
||||
*
|
||||
* @return boolean Whether this object has a value assigned.
|
||||
*/
|
||||
public boolean hasValue() {
|
||||
return mHasValue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value for this Keyframe.
|
||||
*
|
||||
* @return The value for this Keyframe.
|
||||
*/
|
||||
public abstract Object getValue();
|
||||
|
||||
/**
|
||||
* Sets the value for this Keyframe.
|
||||
*
|
||||
* @param value value for this Keyframe.
|
||||
*/
|
||||
public abstract void setValue(Object value);
|
||||
|
||||
/**
|
||||
* Gets the time for this keyframe, as a fraction of the overall animation duration.
|
||||
*
|
||||
* @return The time associated with this keyframe, as a fraction of the overall animation
|
||||
* duration. This should be a value between 0 and 1.
|
||||
*/
|
||||
public float getFraction() {
|
||||
return mFraction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the time for this keyframe, as a fraction of the overall animation duration.
|
||||
*
|
||||
* @param fraction time associated with this keyframe, as a fraction of the overall animation
|
||||
* duration. This should be a value between 0 and 1.
|
||||
*/
|
||||
public void setFraction(float fraction) {
|
||||
mFraction = fraction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the optional interpolator for this Keyframe. A value of <code>null</code> indicates
|
||||
* that there is no interpolation, which is the same as linear interpolation.
|
||||
*
|
||||
* @return The optional interpolator for this Keyframe.
|
||||
*/
|
||||
public /*Time*/Interpolator getInterpolator() {
|
||||
return mInterpolator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the optional interpolator for this Keyframe. A value of <code>null</code> indicates
|
||||
* that there is no interpolation, which is the same as linear interpolation.
|
||||
*
|
||||
* @return The optional interpolator for this Keyframe.
|
||||
*/
|
||||
public void setInterpolator(/*Time*/Interpolator interpolator) {
|
||||
mInterpolator = interpolator;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the type of keyframe. This information is used by ValueAnimator to determine the type of
|
||||
* {@link TypeEvaluator} to use when calculating values between keyframes. The type is based
|
||||
* on the type of Keyframe created.
|
||||
*
|
||||
* @return The type of the value stored in the Keyframe.
|
||||
*/
|
||||
public Class getType() {
|
||||
return mValueType;
|
||||
}
|
||||
|
||||
@Override
|
||||
public abstract Keyframe clone();
|
||||
|
||||
/**
|
||||
* This internal subclass is used for all types which are not int or float.
|
||||
*/
|
||||
static class ObjectKeyframe extends Keyframe {
|
||||
|
||||
/**
|
||||
* The value of the animation at the time mFraction.
|
||||
*/
|
||||
Object mValue;
|
||||
|
||||
ObjectKeyframe(float fraction, Object value) {
|
||||
mFraction = fraction;
|
||||
mValue = value;
|
||||
mHasValue = (value != null);
|
||||
mValueType = mHasValue ? value.getClass() : Object.class;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
mValue = value;
|
||||
mHasValue = (value != null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectKeyframe clone() {
|
||||
ObjectKeyframe kfClone = new ObjectKeyframe(getFraction(), mValue);
|
||||
kfClone.setInterpolator(getInterpolator());
|
||||
return kfClone;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal subclass used when the keyframe value is of type int.
|
||||
*/
|
||||
static class IntKeyframe extends Keyframe {
|
||||
|
||||
/**
|
||||
* The value of the animation at the time mFraction.
|
||||
*/
|
||||
int mValue;
|
||||
|
||||
IntKeyframe(float fraction, int value) {
|
||||
mFraction = fraction;
|
||||
mValue = value;
|
||||
mValueType = int.class;
|
||||
mHasValue = true;
|
||||
}
|
||||
|
||||
IntKeyframe(float fraction) {
|
||||
mFraction = fraction;
|
||||
mValueType = int.class;
|
||||
}
|
||||
|
||||
public int getIntValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
if (value != null && value.getClass() == Integer.class) {
|
||||
mValue = ((Integer)value).intValue();
|
||||
mHasValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public IntKeyframe clone() {
|
||||
IntKeyframe kfClone = new IntKeyframe(getFraction(), mValue);
|
||||
kfClone.setInterpolator(getInterpolator());
|
||||
return kfClone;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Internal subclass used when the keyframe value is of type float.
|
||||
*/
|
||||
static class FloatKeyframe extends Keyframe {
|
||||
/**
|
||||
* The value of the animation at the time mFraction.
|
||||
*/
|
||||
float mValue;
|
||||
|
||||
FloatKeyframe(float fraction, float value) {
|
||||
mFraction = fraction;
|
||||
mValue = value;
|
||||
mValueType = float.class;
|
||||
mHasValue = true;
|
||||
}
|
||||
|
||||
FloatKeyframe(float fraction) {
|
||||
mFraction = fraction;
|
||||
mValueType = float.class;
|
||||
}
|
||||
|
||||
public float getFloatValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public Object getValue() {
|
||||
return mValue;
|
||||
}
|
||||
|
||||
public void setValue(Object value) {
|
||||
if (value != null && value.getClass() == Float.class) {
|
||||
mValue = ((Float)value).floatValue();
|
||||
mHasValue = true;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public FloatKeyframe clone() {
|
||||
FloatKeyframe kfClone = new FloatKeyframe(getFraction(), mValue);
|
||||
kfClone.setInterpolator(getInterpolator());
|
||||
return kfClone;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,227 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.nineoldandroids.animation;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.Keyframe.FloatKeyframe;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.Keyframe.IntKeyframe;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.Keyframe.ObjectKeyframe;
|
||||
|
||||
/**
|
||||
* This class holds a collection of Keyframe objects and is called by ValueAnimator to calculate
|
||||
* values between those keyframes for a given animation. The class internal to the animation
|
||||
* package because it is an implementation detail of how Keyframes are stored and used.
|
||||
*/
|
||||
@SuppressWarnings({"rawtypes", "unchecked"})
|
||||
class KeyframeSet {
|
||||
|
||||
int mNumKeyframes;
|
||||
|
||||
Keyframe mFirstKeyframe;
|
||||
Keyframe mLastKeyframe;
|
||||
/*Time*/Interpolator mInterpolator; // only used in the 2-keyframe case
|
||||
ArrayList<Keyframe> mKeyframes; // only used when there are not 2 keyframes
|
||||
TypeEvaluator mEvaluator;
|
||||
|
||||
|
||||
public KeyframeSet(Keyframe... keyframes) {
|
||||
mNumKeyframes = keyframes.length;
|
||||
mKeyframes = new ArrayList<Keyframe>();
|
||||
mKeyframes.addAll(Arrays.asList(keyframes));
|
||||
mFirstKeyframe = mKeyframes.get(0);
|
||||
mLastKeyframe = mKeyframes.get(mNumKeyframes - 1);
|
||||
mInterpolator = mLastKeyframe.getInterpolator();
|
||||
}
|
||||
|
||||
public static KeyframeSet ofInt(int... values) {
|
||||
int numKeyframes = values.length;
|
||||
IntKeyframe keyframes[] = new IntKeyframe[Math.max(numKeyframes,2)];
|
||||
if (numKeyframes == 1) {
|
||||
keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f);
|
||||
keyframes[1] = (IntKeyframe) Keyframe.ofInt(1f, values[0]);
|
||||
} else {
|
||||
keyframes[0] = (IntKeyframe) Keyframe.ofInt(0f, values[0]);
|
||||
for (int i = 1; i < numKeyframes; ++i) {
|
||||
keyframes[i] = (IntKeyframe) Keyframe.ofInt((float) i / (numKeyframes - 1), values[i]);
|
||||
}
|
||||
}
|
||||
return new IntKeyframeSet(keyframes);
|
||||
}
|
||||
|
||||
public static KeyframeSet ofFloat(float... values) {
|
||||
int numKeyframes = values.length;
|
||||
FloatKeyframe keyframes[] = new FloatKeyframe[Math.max(numKeyframes,2)];
|
||||
if (numKeyframes == 1) {
|
||||
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f);
|
||||
keyframes[1] = (FloatKeyframe) Keyframe.ofFloat(1f, values[0]);
|
||||
} else {
|
||||
keyframes[0] = (FloatKeyframe) Keyframe.ofFloat(0f, values[0]);
|
||||
for (int i = 1; i < numKeyframes; ++i) {
|
||||
keyframes[i] = (FloatKeyframe) Keyframe.ofFloat((float) i / (numKeyframes - 1), values[i]);
|
||||
}
|
||||
}
|
||||
return new FloatKeyframeSet(keyframes);
|
||||
}
|
||||
|
||||
public static KeyframeSet ofKeyframe(Keyframe... keyframes) {
|
||||
// if all keyframes of same primitive type, create the appropriate KeyframeSet
|
||||
int numKeyframes = keyframes.length;
|
||||
boolean hasFloat = false;
|
||||
boolean hasInt = false;
|
||||
boolean hasOther = false;
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
if (keyframes[i] instanceof FloatKeyframe) {
|
||||
hasFloat = true;
|
||||
} else if (keyframes[i] instanceof IntKeyframe) {
|
||||
hasInt = true;
|
||||
} else {
|
||||
hasOther = true;
|
||||
}
|
||||
}
|
||||
if (hasFloat && !hasInt && !hasOther) {
|
||||
FloatKeyframe floatKeyframes[] = new FloatKeyframe[numKeyframes];
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
floatKeyframes[i] = (FloatKeyframe) keyframes[i];
|
||||
}
|
||||
return new FloatKeyframeSet(floatKeyframes);
|
||||
} else if (hasInt && !hasFloat && !hasOther) {
|
||||
IntKeyframe intKeyframes[] = new IntKeyframe[numKeyframes];
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
intKeyframes[i] = (IntKeyframe) keyframes[i];
|
||||
}
|
||||
return new IntKeyframeSet(intKeyframes);
|
||||
} else {
|
||||
return new KeyframeSet(keyframes);
|
||||
}
|
||||
}
|
||||
|
||||
public static KeyframeSet ofObject(Object... values) {
|
||||
int numKeyframes = values.length;
|
||||
ObjectKeyframe keyframes[] = new ObjectKeyframe[Math.max(numKeyframes,2)];
|
||||
if (numKeyframes == 1) {
|
||||
keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f);
|
||||
keyframes[1] = (ObjectKeyframe) Keyframe.ofObject(1f, values[0]);
|
||||
} else {
|
||||
keyframes[0] = (ObjectKeyframe) Keyframe.ofObject(0f, values[0]);
|
||||
for (int i = 1; i < numKeyframes; ++i) {
|
||||
keyframes[i] = (ObjectKeyframe) Keyframe.ofObject((float) i / (numKeyframes - 1), values[i]);
|
||||
}
|
||||
}
|
||||
return new KeyframeSet(keyframes);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the TypeEvaluator to be used when calculating animated values. This object
|
||||
* is required only for KeyframeSets that are not either IntKeyframeSet or FloatKeyframeSet,
|
||||
* both of which assume their own evaluator to speed up calculations with those primitive
|
||||
* types.
|
||||
*
|
||||
* @param evaluator The TypeEvaluator to be used to calculate animated values.
|
||||
*/
|
||||
public void setEvaluator(TypeEvaluator evaluator) {
|
||||
mEvaluator = evaluator;
|
||||
}
|
||||
|
||||
@Override
|
||||
public KeyframeSet clone() {
|
||||
ArrayList<Keyframe> keyframes = mKeyframes;
|
||||
int numKeyframes = mKeyframes.size();
|
||||
Keyframe[] newKeyframes = new Keyframe[numKeyframes];
|
||||
for (int i = 0; i < numKeyframes; ++i) {
|
||||
newKeyframes[i] = keyframes.get(i).clone();
|
||||
}
|
||||
KeyframeSet newSet = new KeyframeSet(newKeyframes);
|
||||
return newSet;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the animated value, given the elapsed fraction of the animation (interpolated by the
|
||||
* animation's interpolator) and the evaluator used to calculate in-between values. This
|
||||
* function maps the input fraction to the appropriate keyframe interval and a fraction
|
||||
* between them and returns the interpolated value. Note that the input fraction may fall
|
||||
* outside the [0-1] bounds, if the animation's interpolator made that happen (e.g., a
|
||||
* spring interpolation that might send the fraction past 1.0). We handle this situation by
|
||||
* just using the two keyframes at the appropriate end when the value is outside those bounds.
|
||||
*
|
||||
* @param fraction The elapsed fraction of the animation
|
||||
* @return The animated value.
|
||||
*/
|
||||
public Object getValue(float fraction) {
|
||||
|
||||
// Special-case optimization for the common case of only two keyframes
|
||||
if (mNumKeyframes == 2) {
|
||||
if (mInterpolator != null) {
|
||||
fraction = mInterpolator.getInterpolation(fraction);
|
||||
}
|
||||
return mEvaluator.evaluate(fraction, mFirstKeyframe.getValue(),
|
||||
mLastKeyframe.getValue());
|
||||
}
|
||||
if (fraction <= 0f) {
|
||||
final Keyframe nextKeyframe = mKeyframes.get(1);
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
final float prevFraction = mFirstKeyframe.getFraction();
|
||||
float intervalFraction = (fraction - prevFraction) /
|
||||
(nextKeyframe.getFraction() - prevFraction);
|
||||
return mEvaluator.evaluate(intervalFraction, mFirstKeyframe.getValue(),
|
||||
nextKeyframe.getValue());
|
||||
} else if (fraction >= 1f) {
|
||||
final Keyframe prevKeyframe = mKeyframes.get(mNumKeyframes - 2);
|
||||
final /*Time*/Interpolator interpolator = mLastKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
final float prevFraction = prevKeyframe.getFraction();
|
||||
float intervalFraction = (fraction - prevFraction) /
|
||||
(mLastKeyframe.getFraction() - prevFraction);
|
||||
return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
|
||||
mLastKeyframe.getValue());
|
||||
}
|
||||
Keyframe prevKeyframe = mFirstKeyframe;
|
||||
for (int i = 1; i < mNumKeyframes; ++i) {
|
||||
Keyframe nextKeyframe = mKeyframes.get(i);
|
||||
if (fraction < nextKeyframe.getFraction()) {
|
||||
final /*Time*/Interpolator interpolator = nextKeyframe.getInterpolator();
|
||||
if (interpolator != null) {
|
||||
fraction = interpolator.getInterpolation(fraction);
|
||||
}
|
||||
final float prevFraction = prevKeyframe.getFraction();
|
||||
float intervalFraction = (fraction - prevFraction) /
|
||||
(nextKeyframe.getFraction() - prevFraction);
|
||||
return mEvaluator.evaluate(intervalFraction, prevKeyframe.getValue(),
|
||||
nextKeyframe.getValue());
|
||||
}
|
||||
prevKeyframe = nextKeyframe;
|
||||
}
|
||||
// shouldn't reach here
|
||||
return mLastKeyframe.getValue();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String returnVal = " ";
|
||||
for (int i = 0; i < mNumKeyframes; ++i) {
|
||||
returnVal += mKeyframes.get(i).getValue() + " ";
|
||||
}
|
||||
return returnVal;
|
||||
}
|
||||
}
|
|
@ -1,491 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.nineoldandroids.animation;
|
||||
|
||||
import android.util.Log;
|
||||
//import android.util.Property;
|
||||
|
||||
//import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
|
||||
/**
|
||||
* This subclass of {@link ValueAnimator} provides support for animating properties on target objects.
|
||||
* The constructors of this class take parameters to define the target object that will be animated
|
||||
* as well as the name of the property that will be animated. Appropriate set/get functions
|
||||
* are then determined internally and the animation will call these functions as necessary to
|
||||
* animate the property.
|
||||
*
|
||||
* @see #setPropertyName(String)
|
||||
*
|
||||
*/
|
||||
@SuppressWarnings("rawtypes")
|
||||
public final class ObjectAnimator extends ValueAnimator {
|
||||
private static final boolean DBG = false;
|
||||
|
||||
// The target object on which the property exists, set in the constructor
|
||||
private Object mTarget;
|
||||
|
||||
private String mPropertyName;
|
||||
|
||||
//private Property mProperty;
|
||||
|
||||
/**
|
||||
* Sets the name of the property that will be animated. This name is used to derive
|
||||
* a setter function that will be called to set animated values.
|
||||
* For example, a property name of <code>foo</code> will result
|
||||
* in a call to the function <code>setFoo()</code> on the target object. If either
|
||||
* <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
|
||||
* also be derived and called.
|
||||
*
|
||||
* <p>For best performance of the mechanism that calls the setter function determined by the
|
||||
* name of the property being animated, use <code>float</code> or <code>int</code> typed values,
|
||||
* and make the setter function for those properties have a <code>void</code> return value. This
|
||||
* will cause the code to take an optimized path for these constrained circumstances. Other
|
||||
* property types and return types will work, but will have more overhead in processing
|
||||
* the requests due to normal reflection mechanisms.</p>
|
||||
*
|
||||
* <p>Note that the setter function derived from this property name
|
||||
* must take the same parameter type as the
|
||||
* <code>valueFrom</code> and <code>valueTo</code> properties, otherwise the call to
|
||||
* the setter function will fail.</p>
|
||||
*
|
||||
* <p>If this ObjectAnimator has been set up to animate several properties together,
|
||||
* using more than one PropertyValuesHolder objects, then setting the propertyName simply
|
||||
* sets the propertyName in the first of those PropertyValuesHolder objects.</p>
|
||||
*
|
||||
* @param propertyName The name of the property being animated. Should not be null.
|
||||
*/
|
||||
public void setPropertyName(String propertyName) {
|
||||
// mValues could be null if this is being constructed piecemeal. Just record the
|
||||
// propertyName to be used later when setValues() is called if so.
|
||||
if (mValues != null) {
|
||||
PropertyValuesHolder valuesHolder = mValues[0];
|
||||
String oldName = valuesHolder.getPropertyName();
|
||||
valuesHolder.setPropertyName(propertyName);
|
||||
mValuesMap.remove(oldName);
|
||||
mValuesMap.put(propertyName, valuesHolder);
|
||||
}
|
||||
mPropertyName = propertyName;
|
||||
// New property/values/target should cause re-initialization prior to starting
|
||||
mInitialized = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the property that will be animated. Property objects will take precedence over
|
||||
* properties specified by the {@link #setPropertyName(String)} method. Animations should
|
||||
* be set up to use one or the other, not both.
|
||||
*
|
||||
* @param property The property being animated. Should not be null.
|
||||
*/
|
||||
//public void setProperty(Property property) {
|
||||
// // mValues could be null if this is being constructed piecemeal. Just record the
|
||||
// // propertyName to be used later when setValues() is called if so.
|
||||
// if (mValues != null) {
|
||||
// PropertyValuesHolder valuesHolder = mValues[0];
|
||||
// String oldName = valuesHolder.getPropertyName();
|
||||
// valuesHolder.setProperty(property);
|
||||
// mValuesMap.remove(oldName);
|
||||
// mValuesMap.put(mPropertyName, valuesHolder);
|
||||
// }
|
||||
// if (mProperty != null) {
|
||||
// mPropertyName = property.getName();
|
||||
// }
|
||||
// mProperty = property;
|
||||
// // New property/values/target should cause re-initialization prior to starting
|
||||
// mInitialized = false;
|
||||
//}
|
||||
|
||||
/**
|
||||
* Gets the name of the property that will be animated. This name will be used to derive
|
||||
* a setter function that will be called to set animated values.
|
||||
* For example, a property name of <code>foo</code> will result
|
||||
* in a call to the function <code>setFoo()</code> on the target object. If either
|
||||
* <code>valueFrom</code> or <code>valueTo</code> is null, then a getter function will
|
||||
* also be derived and called.
|
||||
*/
|
||||
public String getPropertyName() {
|
||||
return mPropertyName;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new ObjectAnimator object. This default constructor is primarily for
|
||||
* use internally; the other constructors which take parameters are more generally
|
||||
* useful.
|
||||
*/
|
||||
public ObjectAnimator() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Private utility constructor that initializes the target object and name of the
|
||||
* property being animated.
|
||||
*
|
||||
* @param target The object whose property is to be animated. This object should
|
||||
* have a public method on it called <code>setName()</code>, where <code>name</code> is
|
||||
* the value of the <code>propertyName</code> parameter.
|
||||
* @param propertyName The name of the property being animated.
|
||||
*/
|
||||
private ObjectAnimator(Object target, String propertyName) {
|
||||
mTarget = target;
|
||||
setPropertyName(propertyName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Private utility constructor that initializes the target object and property being animated.
|
||||
*
|
||||
* @param target The object whose property is to be animated.
|
||||
* @param property The property being animated.
|
||||
*/
|
||||
//private <T> ObjectAnimator(T target, Property<T, ?> property) {
|
||||
// mTarget = target;
|
||||
// setProperty(property);
|
||||
//}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between int values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated. This object should
|
||||
* have a public method on it called <code>setName()</code>, where <code>name</code> is
|
||||
* the value of the <code>propertyName</code> parameter.
|
||||
* @param propertyName The name of the property being animated.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
public static ObjectAnimator ofInt(Object target, String propertyName, int... values) {
|
||||
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
|
||||
anim.setIntValues(values);
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between int values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated.
|
||||
* @param property The property being animated.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
//public static <T> ObjectAnimator ofInt(T target, Property<T, Integer> property, int... values) {
|
||||
// ObjectAnimator anim = new ObjectAnimator(target, property);
|
||||
// anim.setIntValues(values);
|
||||
// return anim;
|
||||
//}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between float values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated. This object should
|
||||
* have a public method on it called <code>setName()</code>, where <code>name</code> is
|
||||
* the value of the <code>propertyName</code> parameter.
|
||||
* @param propertyName The name of the property being animated.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
|
||||
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
|
||||
anim.setFloatValues(values);
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between float values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated.
|
||||
* @param property The property being animated.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
//public static <T> ObjectAnimator ofFloat(T target, Property<T, Float> property,
|
||||
// float... values) {
|
||||
// ObjectAnimator anim = new ObjectAnimator(target, property);
|
||||
// anim.setFloatValues(values);
|
||||
// return anim;
|
||||
//}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between Object values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated. This object should
|
||||
* have a public method on it called <code>setName()</code>, where <code>name</code> is
|
||||
* the value of the <code>propertyName</code> parameter.
|
||||
* @param propertyName The name of the property being animated.
|
||||
* @param evaluator A TypeEvaluator that will be called on each animation frame to
|
||||
* provide the necessary interpolation between the Object values to derive the animated
|
||||
* value.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
public static ObjectAnimator ofObject(Object target, String propertyName,
|
||||
TypeEvaluator evaluator, Object... values) {
|
||||
ObjectAnimator anim = new ObjectAnimator(target, propertyName);
|
||||
anim.setObjectValues(values);
|
||||
anim.setEvaluator(evaluator);
|
||||
return anim;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between Object values. A single
|
||||
* value implies that that value is the one being animated to. Two values imply a starting
|
||||
* and ending values. More than two values imply a starting value, values to animate through
|
||||
* along the way, and an ending value (these values will be distributed evenly across
|
||||
* the duration of the animation).
|
||||
*
|
||||
* @param target The object whose property is to be animated.
|
||||
* @param property The property being animated.
|
||||
* @param evaluator A TypeEvaluator that will be called on each animation frame to
|
||||
* provide the necessary interpolation between the Object values to derive the animated
|
||||
* value.
|
||||
* @param values A set of values that the animation will animate between over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
//public static <T, V> ObjectAnimator ofObject(T target, Property<T, V> property,
|
||||
// TypeEvaluator<V> evaluator, V... values) {
|
||||
// ObjectAnimator anim = new ObjectAnimator(target, property);
|
||||
// anim.setObjectValues(values);
|
||||
// anim.setEvaluator(evaluator);
|
||||
// return anim;
|
||||
//}
|
||||
|
||||
/**
|
||||
* Constructs and returns an ObjectAnimator that animates between the sets of values specified
|
||||
* in <code>PropertyValueHolder</code> objects. This variant should be used when animating
|
||||
* several properties at once with the same ObjectAnimator, since PropertyValuesHolder allows
|
||||
* you to associate a set of animation values with a property name.
|
||||
*
|
||||
* @param target The object whose property is to be animated. Depending on how the
|
||||
* PropertyValuesObjects were constructed, the target object should either have the {@link
|
||||
* android.util.Property} objects used to construct the PropertyValuesHolder objects or (if the
|
||||
* PropertyValuesHOlder objects were created with property names) the target object should have
|
||||
* public methods on it called <code>setName()</code>, where <code>name</code> is the name of
|
||||
* the property passed in as the <code>propertyName</code> parameter for each of the
|
||||
* PropertyValuesHolder objects.
|
||||
* @param values A set of PropertyValuesHolder objects whose values will be animated between
|
||||
* over time.
|
||||
* @return An ObjectAnimator object that is set up to animate between the given values.
|
||||
*/
|
||||
public static ObjectAnimator ofPropertyValuesHolder(Object target,
|
||||
PropertyValuesHolder... values) {
|
||||
ObjectAnimator anim = new ObjectAnimator();
|
||||
anim.mTarget = target;
|
||||
anim.setValues(values);
|
||||
return anim;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setIntValues(int... values) {
|
||||
if (mValues == null || mValues.length == 0) {
|
||||
// No values yet - this animator is being constructed piecemeal. Init the values with
|
||||
// whatever the current propertyName is
|
||||
//if (mProperty != null) {
|
||||
// setValues(PropertyValuesHolder.ofInt(mProperty, values));
|
||||
//} else {
|
||||
setValues(PropertyValuesHolder.ofInt(mPropertyName, values));
|
||||
//}
|
||||
} else {
|
||||
super.setIntValues(values);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFloatValues(float... values) {
|
||||
if (mValues == null || mValues.length == 0) {
|
||||
// No values yet - this animator is being constructed piecemeal. Init the values with
|
||||
// whatever the current propertyName is
|
||||
//if (mProperty != null) {
|
||||
// setValues(PropertyValuesHolder.ofFloat(mProperty, values));
|
||||
//} else {
|
||||
setValues(PropertyValuesHolder.ofFloat(mPropertyName, values));
|
||||
//}
|
||||
} else {
|
||||
super.setFloatValues(values);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setObjectValues(Object... values) {
|
||||
if (mValues == null || mValues.length == 0) {
|
||||
// No values yet - this animator is being constructed piecemeal. Init the values with
|
||||
// whatever the current propertyName is
|
||||
//if (mProperty != null) {
|
||||
// setValues(PropertyValuesHolder.ofObject(mProperty, (TypeEvaluator)null, values));
|
||||
//} else {
|
||||
setValues(PropertyValuesHolder.ofObject(mPropertyName, (TypeEvaluator)null, values));
|
||||
//}
|
||||
} else {
|
||||
super.setObjectValues(values);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
if (DBG) {
|
||||
Log.d("ObjectAnimator", "Anim target, duration: " + mTarget + ", " + getDuration());
|
||||
for (int i = 0; i < mValues.length; ++i) {
|
||||
PropertyValuesHolder pvh = mValues[i];
|
||||
ArrayList<Keyframe> keyframes = pvh.mKeyframeSet.mKeyframes;
|
||||
Log.d("ObjectAnimator", " Values[" + i + "]: " +
|
||||
pvh.getPropertyName() + ", " + keyframes.get(0).getValue() + ", " +
|
||||
keyframes.get(pvh.mKeyframeSet.mNumKeyframes - 1).getValue());
|
||||
}
|
||||
}
|
||||
super.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is called immediately before processing the first animation
|
||||
* frame of an animation. If there is a nonzero <code>startDelay</code>, the
|
||||
* function is called after that delay ends.
|
||||
* It takes care of the final initialization steps for the
|
||||
* animation. This includes setting mEvaluator, if the user has not yet
|
||||
* set it up, and the setter/getter methods, if the user did not supply
|
||||
* them.
|
||||
*
|
||||
* <p>Overriders of this method should call the superclass method to cause
|
||||
* internal mechanisms to be set up correctly.</p>
|
||||
*/
|
||||
@Override
|
||||
void initAnimation() {
|
||||
if (!mInitialized) {
|
||||
// mValueType may change due to setter/getter setup; do this before calling super.init(),
|
||||
// which uses mValueType to set up the default type evaluator.
|
||||
int numValues = mValues.length;
|
||||
for (int i = 0; i < numValues; ++i) {
|
||||
mValues[i].setupSetterAndGetter(mTarget);
|
||||
}
|
||||
super.initAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the length of the animation. The default duration is 300 milliseconds.
|
||||
*
|
||||
* @param duration The length of the animation, in milliseconds.
|
||||
* @return ObjectAnimator The object called with setDuration(). This return
|
||||
* value makes it easier to compose statements together that construct and then set the
|
||||
* duration, as in
|
||||
* <code>ObjectAnimator.ofInt(target, propertyName, 0, 10).setDuration(500).start()</code>.
|
||||
*/
|
||||
@Override
|
||||
public ObjectAnimator setDuration(long duration) {
|
||||
super.setDuration(duration);
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* The target object whose property will be animated by this animation
|
||||
*
|
||||
* @return The object being animated
|
||||
*/
|
||||
public Object getTarget() {
|
||||
return mTarget;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the target object whose property will be animated by this animation
|
||||
*
|
||||
* @param target The object being animated
|
||||
*/
|
||||
@Override
|
||||
public void setTarget(Object target) {
|
||||
if (mTarget != target) {
|
||||
final Object oldTarget = mTarget;
|
||||
mTarget = target;
|
||||
if (oldTarget != null && target != null && oldTarget.getClass() == target.getClass()) {
|
||||
return;
|
||||
}
|
||||
// New target type should cause re-initialization prior to starting
|
||||
mInitialized = false;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupStartValues() {
|
||||
initAnimation();
|
||||
int numValues = mValues.length;
|
||||
for (int i = 0; i < numValues; ++i) {
|
||||
mValues[i].setupStartValue(mTarget);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setupEndValues() {
|
||||
initAnimation();
|
||||
int numValues = mValues.length;
|
||||
for (int i = 0; i < numValues; ++i) {
|
||||
mValues[i].setupEndValue(mTarget);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is called with the elapsed fraction of the animation during every
|
||||
* animation frame. This function turns the elapsed fraction into an interpolated fraction
|
||||
* and then into an animated value (from the evaluator. The function is called mostly during
|
||||
* animation updates, but it is also called when the <code>end()</code>
|
||||
* function is called, to set the final value on the property.
|
||||
*
|
||||
* <p>Overrides of this method must call the superclass to perform the calculation
|
||||
* of the animated value.</p>
|
||||
*
|
||||
* @param fraction The elapsed fraction of the animation.
|
||||
*/
|
||||
@Override
|
||||
void animateValue(float fraction) {
|
||||
super.animateValue(fraction);
|
||||
int numValues = mValues.length;
|
||||
for (int i = 0; i < numValues; ++i) {
|
||||
mValues[i].setAnimatedValue(mTarget);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public ObjectAnimator clone() {
|
||||
final ObjectAnimator anim = (ObjectAnimator) super.clone();
|
||||
return anim;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
String returnVal = "ObjectAnimator@" + Integer.toHexString(hashCode()) + ", target " +
|
||||
mTarget;
|
||||
if (mValues != null) {
|
||||
for (int i = 0; i < mValues.length; ++i) {
|
||||
returnVal += "\n " + mValues[i].toString();
|
||||
}
|
||||
}
|
||||
return returnVal;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,44 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.nineoldandroids.animation;
|
||||
|
||||
/**
|
||||
* Interface for use with the {@link ValueAnimator#setEvaluator(TypeEvaluator)} function. Evaluators
|
||||
* allow developers to create animations on arbitrary property types, by allowing them to supply
|
||||
* custom evaulators for types that are not automatically understood and used by the animation
|
||||
* system.
|
||||
*
|
||||
* @see ValueAnimator#setEvaluator(TypeEvaluator)
|
||||
*/
|
||||
public interface TypeEvaluator<T> {
|
||||
|
||||
/**
|
||||
* This function returns the result of linearly interpolating the start and end values, with
|
||||
* <code>fraction</code> representing the proportion between the start and end values. The
|
||||
* calculation is a simple parametric calculation: <code>result = x0 + t * (v1 - v0)</code>,
|
||||
* where <code>x0</code> is <code>startValue</code>, <code>x1</code> is <code>endValue</code>,
|
||||
* and <code>t</code> is <code>fraction</code>.
|
||||
*
|
||||
* @param fraction The fraction from the starting to the ending values
|
||||
* @param startValue The start value.
|
||||
* @param endValue The end value.
|
||||
* @return A linear interpolation between the start and end values, given the
|
||||
* <code>fraction</code> parameter.
|
||||
*/
|
||||
public T evaluate(float fraction, T startValue, T endValue);
|
||||
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,79 +0,0 @@
|
|||
package com.actionbarsherlock.internal.nineoldandroids.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import com.actionbarsherlock.internal.nineoldandroids.view.animation.AnimatorProxy;
|
||||
|
||||
public abstract class NineViewGroup extends ViewGroup {
|
||||
private final AnimatorProxy mProxy;
|
||||
|
||||
public NineViewGroup(Context context) {
|
||||
super(context);
|
||||
mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null;
|
||||
}
|
||||
public NineViewGroup(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null;
|
||||
}
|
||||
public NineViewGroup(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisibility(int visibility) {
|
||||
if (mProxy != null) {
|
||||
if (visibility == GONE) {
|
||||
clearAnimation();
|
||||
} else if (visibility == VISIBLE) {
|
||||
setAnimation(mProxy);
|
||||
}
|
||||
}
|
||||
super.setVisibility(visibility);
|
||||
}
|
||||
|
||||
public float getAlpha() {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
return mProxy.getAlpha();
|
||||
} else {
|
||||
return super.getAlpha();
|
||||
}
|
||||
}
|
||||
public void setAlpha(float alpha) {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
mProxy.setAlpha(alpha);
|
||||
} else {
|
||||
super.setAlpha(alpha);
|
||||
}
|
||||
}
|
||||
public float getTranslationX() {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
return mProxy.getTranslationX();
|
||||
} else {
|
||||
return super.getTranslationX();
|
||||
}
|
||||
}
|
||||
public void setTranslationX(float translationX) {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
mProxy.setTranslationX(translationX);
|
||||
} else {
|
||||
super.setTranslationX(translationX);
|
||||
}
|
||||
}
|
||||
public float getTranslationY() {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
return mProxy.getTranslationY();
|
||||
} else {
|
||||
return super.getTranslationY();
|
||||
}
|
||||
}
|
||||
public void setTranslationY(float translationY) {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
mProxy.setTranslationY(translationY);
|
||||
} else {
|
||||
super.setTranslationY(translationY);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,212 +0,0 @@
|
|||
package com.actionbarsherlock.internal.nineoldandroids.view.animation;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
import java.util.WeakHashMap;
|
||||
import android.graphics.Matrix;
|
||||
import android.graphics.RectF;
|
||||
import android.os.Build;
|
||||
import android.util.FloatMath;
|
||||
import android.view.View;
|
||||
import android.view.animation.Animation;
|
||||
import android.view.animation.Transformation;
|
||||
|
||||
public final class AnimatorProxy extends Animation {
|
||||
public static final boolean NEEDS_PROXY = Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB;
|
||||
|
||||
private static final WeakHashMap<View, AnimatorProxy> PROXIES =
|
||||
new WeakHashMap<View, AnimatorProxy>();
|
||||
|
||||
public static AnimatorProxy wrap(View view) {
|
||||
AnimatorProxy proxy = PROXIES.get(view);
|
||||
if (proxy == null) {
|
||||
proxy = new AnimatorProxy(view);
|
||||
PROXIES.put(view, proxy);
|
||||
}
|
||||
return proxy;
|
||||
}
|
||||
|
||||
private final WeakReference<View> mView;
|
||||
|
||||
private float mAlpha = 1;
|
||||
private float mScaleX = 1;
|
||||
private float mScaleY = 1;
|
||||
private float mTranslationX;
|
||||
private float mTranslationY;
|
||||
|
||||
private final RectF mBefore = new RectF();
|
||||
private final RectF mAfter = new RectF();
|
||||
private final Matrix mTempMatrix = new Matrix();
|
||||
|
||||
private AnimatorProxy(View view) {
|
||||
setDuration(0); //perform transformation immediately
|
||||
setFillAfter(true); //persist transformation beyond duration
|
||||
view.setAnimation(this);
|
||||
mView = new WeakReference<View>(view);
|
||||
}
|
||||
|
||||
public float getAlpha() {
|
||||
return mAlpha;
|
||||
}
|
||||
public void setAlpha(float alpha) {
|
||||
if (mAlpha != alpha) {
|
||||
mAlpha = alpha;
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
view.invalidate();
|
||||
}
|
||||
}
|
||||
}
|
||||
public float getScaleX() {
|
||||
return mScaleX;
|
||||
}
|
||||
public void setScaleX(float scaleX) {
|
||||
if (mScaleX != scaleX) {
|
||||
prepareForUpdate();
|
||||
mScaleX = scaleX;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
public float getScaleY() {
|
||||
return mScaleY;
|
||||
}
|
||||
public void setScaleY(float scaleY) {
|
||||
if (mScaleY != scaleY) {
|
||||
prepareForUpdate();
|
||||
mScaleY = scaleY;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
public int getScrollX() {
|
||||
View view = mView.get();
|
||||
if (view == null) {
|
||||
return 0;
|
||||
}
|
||||
return view.getScrollX();
|
||||
}
|
||||
public void setScrollX(int value) {
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
view.scrollTo(value, view.getScrollY());
|
||||
}
|
||||
}
|
||||
public int getScrollY() {
|
||||
View view = mView.get();
|
||||
if (view == null) {
|
||||
return 0;
|
||||
}
|
||||
return view.getScrollY();
|
||||
}
|
||||
public void setScrollY(int value) {
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
view.scrollTo(view.getScrollY(), value);
|
||||
}
|
||||
}
|
||||
|
||||
public float getTranslationX() {
|
||||
return mTranslationX;
|
||||
}
|
||||
public void setTranslationX(float translationX) {
|
||||
if (mTranslationX != translationX) {
|
||||
prepareForUpdate();
|
||||
mTranslationX = translationX;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
public float getTranslationY() {
|
||||
return mTranslationY;
|
||||
}
|
||||
public void setTranslationY(float translationY) {
|
||||
if (mTranslationY != translationY) {
|
||||
prepareForUpdate();
|
||||
mTranslationY = translationY;
|
||||
invalidateAfterUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
private void prepareForUpdate() {
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
computeRect(mBefore, view);
|
||||
}
|
||||
}
|
||||
private void invalidateAfterUpdate() {
|
||||
View view = mView.get();
|
||||
if (view == null) {
|
||||
return;
|
||||
}
|
||||
View parent = (View)view.getParent();
|
||||
if (parent == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
view.setAnimation(this);
|
||||
|
||||
final RectF after = mAfter;
|
||||
computeRect(after, view);
|
||||
after.union(mBefore);
|
||||
|
||||
parent.invalidate(
|
||||
(int) FloatMath.floor(after.left),
|
||||
(int) FloatMath.floor(after.top),
|
||||
(int) FloatMath.ceil(after.right),
|
||||
(int) FloatMath.ceil(after.bottom));
|
||||
}
|
||||
|
||||
private void computeRect(final RectF r, View view) {
|
||||
// compute current rectangle according to matrix transformation
|
||||
final float w = view.getWidth();
|
||||
final float h = view.getHeight();
|
||||
|
||||
// use a rectangle at 0,0 to make sure we don't run into issues with scaling
|
||||
r.set(0, 0, w, h);
|
||||
|
||||
final Matrix m = mTempMatrix;
|
||||
m.reset();
|
||||
transformMatrix(m, view);
|
||||
mTempMatrix.mapRect(r);
|
||||
|
||||
r.offset(view.getLeft(), view.getTop());
|
||||
|
||||
// Straighten coords if rotations flipped them
|
||||
if (r.right < r.left) {
|
||||
final float f = r.right;
|
||||
r.right = r.left;
|
||||
r.left = f;
|
||||
}
|
||||
if (r.bottom < r.top) {
|
||||
final float f = r.top;
|
||||
r.top = r.bottom;
|
||||
r.bottom = f;
|
||||
}
|
||||
}
|
||||
|
||||
private void transformMatrix(Matrix m, View view) {
|
||||
final float w = view.getWidth();
|
||||
final float h = view.getHeight();
|
||||
|
||||
final float sX = mScaleX;
|
||||
final float sY = mScaleY;
|
||||
if ((sX != 1.0f) || (sY != 1.0f)) {
|
||||
final float deltaSX = ((sX * w) - w) / 2f;
|
||||
final float deltaSY = ((sY * h) - h) / 2f;
|
||||
m.postScale(sX, sY);
|
||||
m.postTranslate(-deltaSX, -deltaSY);
|
||||
}
|
||||
m.postTranslate(mTranslationX, mTranslationY);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void applyTransformation(float interpolatedTime, Transformation t) {
|
||||
View view = mView.get();
|
||||
if (view != null) {
|
||||
t.setAlpha(mAlpha);
|
||||
transformMatrix(t.getMatrix(), view);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
/* Do nothing. */
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
package com.actionbarsherlock.internal.nineoldandroids.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.FrameLayout;
|
||||
|
||||
import com.actionbarsherlock.internal.nineoldandroids.view.animation.AnimatorProxy;
|
||||
|
||||
public class NineFrameLayout extends FrameLayout {
|
||||
private final AnimatorProxy mProxy;
|
||||
|
||||
public NineFrameLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisibility(int visibility) {
|
||||
if (mProxy != null) {
|
||||
if (visibility == GONE) {
|
||||
clearAnimation();
|
||||
} else if (visibility == VISIBLE) {
|
||||
setAnimation(mProxy);
|
||||
}
|
||||
}
|
||||
super.setVisibility(visibility);
|
||||
}
|
||||
|
||||
public float getAlpha() {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
return mProxy.getAlpha();
|
||||
} else {
|
||||
return super.getAlpha();
|
||||
}
|
||||
}
|
||||
public void setAlpha(float alpha) {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
mProxy.setAlpha(alpha);
|
||||
} else {
|
||||
super.setAlpha(alpha);
|
||||
}
|
||||
}
|
||||
public float getTranslationY() {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
return mProxy.getTranslationY();
|
||||
} else {
|
||||
return super.getTranslationY();
|
||||
}
|
||||
}
|
||||
public void setTranslationY(float translationY) {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
mProxy.setTranslationY(translationY);
|
||||
} else {
|
||||
super.setTranslationY(translationY);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,41 +0,0 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
package com.actionbarsherlock.internal.nineoldandroids.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.actionbarsherlock.internal.nineoldandroids.view.animation.AnimatorProxy;
|
||||
|
||||
public class NineLinearLayout extends LinearLayout {
|
||||
private final AnimatorProxy mProxy;
|
||||
|
||||
public NineLinearLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mProxy = AnimatorProxy.NEEDS_PROXY ? AnimatorProxy.wrap(this) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisibility(int visibility) {
|
||||
if (mProxy != null) {
|
||||
if (visibility == GONE) {
|
||||
clearAnimation();
|
||||
} else if (visibility == VISIBLE) {
|
||||
setAnimation(mProxy);
|
||||
}
|
||||
}
|
||||
super.setVisibility(visibility);
|
||||
}
|
||||
|
||||
public float getAlpha() {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
return mProxy.getAlpha();
|
||||
} else {
|
||||
return super.getAlpha();
|
||||
}
|
||||
}
|
||||
public void setAlpha(float alpha) {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
mProxy.setAlpha(alpha);
|
||||
} else {
|
||||
super.setAlpha(alpha);
|
||||
}
|
||||
}
|
||||
public float getTranslationX() {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
return mProxy.getTranslationX();
|
||||
} else {
|
||||
return super.getTranslationX();
|
||||
}
|
||||
}
|
||||
public void setTranslationX(float translationX) {
|
||||
if (AnimatorProxy.NEEDS_PROXY) {
|
||||
mProxy.setTranslationX(translationX);
|
||||
} else {
|
||||
super.setTranslationX(translationX);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,40 +0,0 @@
|
|||
package com.actionbarsherlock.internal.view;
|
||||
|
||||
import com.actionbarsherlock.internal.view.menu.SubMenuWrapper;
|
||||
import com.actionbarsherlock.view.ActionProvider;
|
||||
import android.view.View;
|
||||
|
||||
public class ActionProviderWrapper extends android.view.ActionProvider {
|
||||
private final ActionProvider mProvider;
|
||||
|
||||
|
||||
public ActionProviderWrapper(ActionProvider provider) {
|
||||
super(null/*TODO*/); //XXX this *should* be unused
|
||||
mProvider = provider;
|
||||
}
|
||||
|
||||
|
||||
public ActionProvider unwrap() {
|
||||
return mProvider;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateActionView() {
|
||||
return mProvider.onCreateActionView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSubMenu() {
|
||||
return mProvider.hasSubMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onPerformDefaultAction() {
|
||||
return mProvider.onPerformDefaultAction();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPrepareSubMenu(android.view.SubMenu subMenu) {
|
||||
mProvider.onPrepareSubMenu(new SubMenuWrapper(subMenu));
|
||||
}
|
||||
}
|
|
@ -1,148 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.actionbarsherlock.internal.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
import com.actionbarsherlock.internal.view.menu.MenuBuilder;
|
||||
import com.actionbarsherlock.internal.view.menu.MenuPopupHelper;
|
||||
import com.actionbarsherlock.internal.view.menu.SubMenuBuilder;
|
||||
import com.actionbarsherlock.internal.widget.ActionBarContextView;
|
||||
import com.actionbarsherlock.view.ActionMode;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuInflater;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
public class StandaloneActionMode extends ActionMode implements MenuBuilder.Callback {
|
||||
private Context mContext;
|
||||
private ActionBarContextView mContextView;
|
||||
private ActionMode.Callback mCallback;
|
||||
private WeakReference<View> mCustomView;
|
||||
private boolean mFinished;
|
||||
private boolean mFocusable;
|
||||
|
||||
private MenuBuilder mMenu;
|
||||
|
||||
public StandaloneActionMode(Context context, ActionBarContextView view,
|
||||
ActionMode.Callback callback, boolean isFocusable) {
|
||||
mContext = context;
|
||||
mContextView = view;
|
||||
mCallback = callback;
|
||||
|
||||
mMenu = new MenuBuilder(context).setDefaultShowAsAction(MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
||||
mMenu.setCallback(this);
|
||||
mFocusable = isFocusable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(CharSequence title) {
|
||||
mContextView.setTitle(title);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSubtitle(CharSequence subtitle) {
|
||||
mContextView.setSubtitle(subtitle);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTitle(int resId) {
|
||||
setTitle(mContext.getString(resId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSubtitle(int resId) {
|
||||
setSubtitle(mContext.getString(resId));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCustomView(View view) {
|
||||
mContextView.setCustomView(view);
|
||||
mCustomView = view != null ? new WeakReference<View>(view) : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
mCallback.onPrepareActionMode(this, mMenu);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
if (mFinished) {
|
||||
return;
|
||||
}
|
||||
mFinished = true;
|
||||
|
||||
mContextView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
|
||||
mCallback.onDestroyActionMode(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Menu getMenu() {
|
||||
return mMenu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTitle() {
|
||||
return mContextView.getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getSubtitle() {
|
||||
return mContextView.getSubtitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getCustomView() {
|
||||
return mCustomView != null ? mCustomView.get() : null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuInflater getMenuInflater() {
|
||||
return new MenuInflater(mContext);
|
||||
}
|
||||
|
||||
public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
|
||||
return mCallback.onActionItemClicked(this, item);
|
||||
}
|
||||
|
||||
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
|
||||
}
|
||||
|
||||
public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
|
||||
if (!subMenu.hasVisibleItems()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
new MenuPopupHelper(mContext, subMenu).show();
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onCloseSubMenu(SubMenuBuilder menu) {
|
||||
}
|
||||
|
||||
public void onMenuModeChange(MenuBuilder menu) {
|
||||
invalidate();
|
||||
mContextView.showOverflowMenu();
|
||||
}
|
||||
|
||||
public boolean isUiFocusable() {
|
||||
return mFocusable;
|
||||
}
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
package com.actionbarsherlock.internal.view;
|
||||
|
||||
public interface View_HasStateListenerSupport {
|
||||
void addOnAttachStateChangeListener(View_OnAttachStateChangeListener listener);
|
||||
void removeOnAttachStateChangeListener(View_OnAttachStateChangeListener listener);
|
||||
}
|
|
@ -1,8 +0,0 @@
|
|||
package com.actionbarsherlock.internal.view;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
public interface View_OnAttachStateChangeListener {
|
||||
void onViewAttachedToWindow(View v);
|
||||
void onViewDetachedFromWindow(View v);
|
||||
}
|
|
@ -1,264 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.ResolveInfo;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import com.actionbarsherlock.view.SubMenu;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ActionMenu implements Menu {
|
||||
private Context mContext;
|
||||
|
||||
private boolean mIsQwerty;
|
||||
|
||||
private ArrayList<ActionMenuItem> mItems;
|
||||
|
||||
public ActionMenu(Context context) {
|
||||
mContext = context;
|
||||
mItems = new ArrayList<ActionMenuItem>();
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
public MenuItem add(CharSequence title) {
|
||||
return add(0, 0, 0, title);
|
||||
}
|
||||
|
||||
public MenuItem add(int titleRes) {
|
||||
return add(0, 0, 0, titleRes);
|
||||
}
|
||||
|
||||
public MenuItem add(int groupId, int itemId, int order, int titleRes) {
|
||||
return add(groupId, itemId, order, mContext.getResources().getString(titleRes));
|
||||
}
|
||||
|
||||
public MenuItem add(int groupId, int itemId, int order, CharSequence title) {
|
||||
ActionMenuItem item = new ActionMenuItem(getContext(),
|
||||
groupId, itemId, 0, order, title);
|
||||
mItems.add(order, item);
|
||||
return item;
|
||||
}
|
||||
|
||||
public int addIntentOptions(int groupId, int itemId, int order,
|
||||
ComponentName caller, Intent[] specifics, Intent intent, int flags,
|
||||
MenuItem[] outSpecificItems) {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
final List<ResolveInfo> lri =
|
||||
pm.queryIntentActivityOptions(caller, specifics, intent, 0);
|
||||
final int N = lri != null ? lri.size() : 0;
|
||||
|
||||
if ((flags & FLAG_APPEND_TO_GROUP) == 0) {
|
||||
removeGroup(groupId);
|
||||
}
|
||||
|
||||
for (int i=0; i<N; i++) {
|
||||
final ResolveInfo ri = lri.get(i);
|
||||
Intent rintent = new Intent(
|
||||
ri.specificIndex < 0 ? intent : specifics[ri.specificIndex]);
|
||||
rintent.setComponent(new ComponentName(
|
||||
ri.activityInfo.applicationInfo.packageName,
|
||||
ri.activityInfo.name));
|
||||
final MenuItem item = add(groupId, itemId, order, ri.loadLabel(pm))
|
||||
.setIcon(ri.loadIcon(pm))
|
||||
.setIntent(rintent);
|
||||
if (outSpecificItems != null && ri.specificIndex >= 0) {
|
||||
outSpecificItems[ri.specificIndex] = item;
|
||||
}
|
||||
}
|
||||
|
||||
return N;
|
||||
}
|
||||
|
||||
public SubMenu addSubMenu(CharSequence title) {
|
||||
// TODO Implement submenus
|
||||
return null;
|
||||
}
|
||||
|
||||
public SubMenu addSubMenu(int titleRes) {
|
||||
// TODO Implement submenus
|
||||
return null;
|
||||
}
|
||||
|
||||
public SubMenu addSubMenu(int groupId, int itemId, int order,
|
||||
CharSequence title) {
|
||||
// TODO Implement submenus
|
||||
return null;
|
||||
}
|
||||
|
||||
public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) {
|
||||
// TODO Implement submenus
|
||||
return null;
|
||||
}
|
||||
|
||||
public void clear() {
|
||||
mItems.clear();
|
||||
}
|
||||
|
||||
public void close() {
|
||||
}
|
||||
|
||||
private int findItemIndex(int id) {
|
||||
final ArrayList<ActionMenuItem> items = mItems;
|
||||
final int itemCount = items.size();
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
if (items.get(i).getItemId() == id) {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
public MenuItem findItem(int id) {
|
||||
return mItems.get(findItemIndex(id));
|
||||
}
|
||||
|
||||
public MenuItem getItem(int index) {
|
||||
return mItems.get(index);
|
||||
}
|
||||
|
||||
public boolean hasVisibleItems() {
|
||||
final ArrayList<ActionMenuItem> items = mItems;
|
||||
final int itemCount = items.size();
|
||||
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
if (items.get(i).isVisible()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private ActionMenuItem findItemWithShortcut(int keyCode, KeyEvent event) {
|
||||
// TODO Make this smarter.
|
||||
final boolean qwerty = mIsQwerty;
|
||||
final ArrayList<ActionMenuItem> items = mItems;
|
||||
final int itemCount = items.size();
|
||||
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
ActionMenuItem item = items.get(i);
|
||||
final char shortcut = qwerty ? item.getAlphabeticShortcut() :
|
||||
item.getNumericShortcut();
|
||||
if (keyCode == shortcut) {
|
||||
return item;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isShortcutKey(int keyCode, KeyEvent event) {
|
||||
return findItemWithShortcut(keyCode, event) != null;
|
||||
}
|
||||
|
||||
public boolean performIdentifierAction(int id, int flags) {
|
||||
final int index = findItemIndex(id);
|
||||
if (index < 0) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return mItems.get(index).invoke();
|
||||
}
|
||||
|
||||
public boolean performShortcut(int keyCode, KeyEvent event, int flags) {
|
||||
ActionMenuItem item = findItemWithShortcut(keyCode, event);
|
||||
if (item == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return item.invoke();
|
||||
}
|
||||
|
||||
public void removeGroup(int groupId) {
|
||||
final ArrayList<ActionMenuItem> items = mItems;
|
||||
int itemCount = items.size();
|
||||
int i = 0;
|
||||
while (i < itemCount) {
|
||||
if (items.get(i).getGroupId() == groupId) {
|
||||
items.remove(i);
|
||||
itemCount--;
|
||||
} else {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void removeItem(int id) {
|
||||
mItems.remove(findItemIndex(id));
|
||||
}
|
||||
|
||||
public void setGroupCheckable(int group, boolean checkable,
|
||||
boolean exclusive) {
|
||||
final ArrayList<ActionMenuItem> items = mItems;
|
||||
final int itemCount = items.size();
|
||||
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
ActionMenuItem item = items.get(i);
|
||||
if (item.getGroupId() == group) {
|
||||
item.setCheckable(checkable);
|
||||
item.setExclusiveCheckable(exclusive);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setGroupEnabled(int group, boolean enabled) {
|
||||
final ArrayList<ActionMenuItem> items = mItems;
|
||||
final int itemCount = items.size();
|
||||
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
ActionMenuItem item = items.get(i);
|
||||
if (item.getGroupId() == group) {
|
||||
item.setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setGroupVisible(int group, boolean visible) {
|
||||
final ArrayList<ActionMenuItem> items = mItems;
|
||||
final int itemCount = items.size();
|
||||
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
ActionMenuItem item = items.get(i);
|
||||
if (item.getGroupId() == group) {
|
||||
item.setVisible(visible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setQwertyMode(boolean isQwerty) {
|
||||
mIsQwerty = isQwerty;
|
||||
}
|
||||
|
||||
public int size() {
|
||||
return mItems.size();
|
||||
}
|
||||
}
|
|
@ -1,278 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.View;
|
||||
|
||||
import com.actionbarsherlock.view.ActionProvider;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import com.actionbarsherlock.view.SubMenu;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ActionMenuItem implements MenuItem {
|
||||
private final int mId;
|
||||
private final int mGroup;
|
||||
//UNUSED private final int mCategoryOrder;
|
||||
private final int mOrdering;
|
||||
|
||||
private CharSequence mTitle;
|
||||
private CharSequence mTitleCondensed;
|
||||
private Intent mIntent;
|
||||
private char mShortcutNumericChar;
|
||||
private char mShortcutAlphabeticChar;
|
||||
|
||||
private Drawable mIconDrawable;
|
||||
//UNUSED private int mIconResId = NO_ICON;
|
||||
|
||||
private Context mContext;
|
||||
|
||||
private MenuItem.OnMenuItemClickListener mClickListener;
|
||||
|
||||
//UNUSED private static final int NO_ICON = 0;
|
||||
|
||||
private int mFlags = ENABLED;
|
||||
private static final int CHECKABLE = 0x00000001;
|
||||
private static final int CHECKED = 0x00000002;
|
||||
private static final int EXCLUSIVE = 0x00000004;
|
||||
private static final int HIDDEN = 0x00000008;
|
||||
private static final int ENABLED = 0x00000010;
|
||||
|
||||
public ActionMenuItem(Context context, int group, int id, int categoryOrder, int ordering,
|
||||
CharSequence title) {
|
||||
mContext = context;
|
||||
mId = id;
|
||||
mGroup = group;
|
||||
//UNUSED mCategoryOrder = categoryOrder;
|
||||
mOrdering = ordering;
|
||||
mTitle = title;
|
||||
}
|
||||
|
||||
public char getAlphabeticShortcut() {
|
||||
return mShortcutAlphabeticChar;
|
||||
}
|
||||
|
||||
public int getGroupId() {
|
||||
return mGroup;
|
||||
}
|
||||
|
||||
public Drawable getIcon() {
|
||||
return mIconDrawable;
|
||||
}
|
||||
|
||||
public Intent getIntent() {
|
||||
return mIntent;
|
||||
}
|
||||
|
||||
public int getItemId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
public ContextMenuInfo getMenuInfo() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public char getNumericShortcut() {
|
||||
return mShortcutNumericChar;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return mOrdering;
|
||||
}
|
||||
|
||||
public SubMenu getSubMenu() {
|
||||
return null;
|
||||
}
|
||||
|
||||
public CharSequence getTitle() {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
public CharSequence getTitleCondensed() {
|
||||
return mTitleCondensed;
|
||||
}
|
||||
|
||||
public boolean hasSubMenu() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isCheckable() {
|
||||
return (mFlags & CHECKABLE) != 0;
|
||||
}
|
||||
|
||||
public boolean isChecked() {
|
||||
return (mFlags & CHECKED) != 0;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return (mFlags & ENABLED) != 0;
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return (mFlags & HIDDEN) == 0;
|
||||
}
|
||||
|
||||
public MenuItem setAlphabeticShortcut(char alphaChar) {
|
||||
mShortcutAlphabeticChar = alphaChar;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setCheckable(boolean checkable) {
|
||||
mFlags = (mFlags & ~CHECKABLE) | (checkable ? CHECKABLE : 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
public ActionMenuItem setExclusiveCheckable(boolean exclusive) {
|
||||
mFlags = (mFlags & ~EXCLUSIVE) | (exclusive ? EXCLUSIVE : 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setChecked(boolean checked) {
|
||||
mFlags = (mFlags & ~CHECKED) | (checked ? CHECKED : 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setEnabled(boolean enabled) {
|
||||
mFlags = (mFlags & ~ENABLED) | (enabled ? ENABLED : 0);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setIcon(Drawable icon) {
|
||||
mIconDrawable = icon;
|
||||
//UNUSED mIconResId = NO_ICON;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setIcon(int iconRes) {
|
||||
//UNUSED mIconResId = iconRes;
|
||||
mIconDrawable = mContext.getResources().getDrawable(iconRes);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setIntent(Intent intent) {
|
||||
mIntent = intent;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setNumericShortcut(char numericChar) {
|
||||
mShortcutNumericChar = numericChar;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) {
|
||||
mClickListener = menuItemClickListener;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setShortcut(char numericChar, char alphaChar) {
|
||||
mShortcutNumericChar = numericChar;
|
||||
mShortcutAlphabeticChar = alphaChar;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setTitle(CharSequence title) {
|
||||
mTitle = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setTitle(int title) {
|
||||
mTitle = mContext.getResources().getString(title);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setTitleCondensed(CharSequence title) {
|
||||
mTitleCondensed = title;
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setVisible(boolean visible) {
|
||||
mFlags = (mFlags & HIDDEN) | (visible ? 0 : HIDDEN);
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean invoke() {
|
||||
if (mClickListener != null && mClickListener.onMenuItemClick(this)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mIntent != null) {
|
||||
mContext.startActivity(mIntent);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setShowAsAction(int show) {
|
||||
// Do nothing. ActionMenuItems always show as action buttons.
|
||||
}
|
||||
|
||||
public MenuItem setActionView(View actionView) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
public View getActionView() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setActionView(int resId) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionProvider getActionProvider() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setActionProvider(ActionProvider actionProvider) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setShowAsActionFlags(int actionEnum) {
|
||||
setShowAsAction(actionEnum);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean expandActionView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collapseActionView() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActionViewExpanded() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setOnActionExpandListener(OnActionExpandListener listener) {
|
||||
// No need to save the listener; ActionMenuItem does not support collapsing items.
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -1,296 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.widget.ImageButton;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.actionbarsherlock.R;
|
||||
import com.actionbarsherlock.internal.view.View_HasStateListenerSupport;
|
||||
import com.actionbarsherlock.internal.view.View_OnAttachStateChangeListener;
|
||||
import com.actionbarsherlock.internal.widget.CapitalizingButton;
|
||||
import com.actionbarsherlock.internal.widget.IcsToast;
|
||||
|
||||
import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getBoolean;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ActionMenuItemView extends LinearLayout
|
||||
implements MenuView.ItemView, View.OnClickListener, View.OnLongClickListener,
|
||||
ActionMenuView.ActionMenuChildView, View_HasStateListenerSupport {
|
||||
//UNUSED private static final String TAG = "ActionMenuItemView";
|
||||
|
||||
private MenuItemImpl mItemData;
|
||||
private CharSequence mTitle;
|
||||
private MenuBuilder.ItemInvoker mItemInvoker;
|
||||
|
||||
private ImageButton mImageButton;
|
||||
private CapitalizingButton mTextButton;
|
||||
private boolean mAllowTextWithIcon;
|
||||
private boolean mExpandedFormat;
|
||||
private int mMinWidth;
|
||||
|
||||
private final Set<View_OnAttachStateChangeListener> mListeners = new HashSet<View_OnAttachStateChangeListener>();
|
||||
|
||||
public ActionMenuItemView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public ActionMenuItemView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public ActionMenuItemView(Context context, AttributeSet attrs, int defStyle) {
|
||||
//TODO super(context, attrs, defStyle);
|
||||
super(context, attrs);
|
||||
mAllowTextWithIcon = getResources_getBoolean(context,
|
||||
R.bool.abs__config_allowActionMenuItemTextWithIcon);
|
||||
TypedArray a = context.obtainStyledAttributes(attrs,
|
||||
R.styleable.SherlockActionMenuItemView, 0, 0);
|
||||
mMinWidth = a.getDimensionPixelSize(
|
||||
R.styleable.SherlockActionMenuItemView_android_minWidth, 0);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOnAttachStateChangeListener(View_OnAttachStateChangeListener listener) {
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeOnAttachStateChangeListener(View_OnAttachStateChangeListener listener) {
|
||||
mListeners.remove(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
for (View_OnAttachStateChangeListener listener : mListeners) {
|
||||
listener.onViewAttachedToWindow(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
for (View_OnAttachStateChangeListener listener : mListeners) {
|
||||
listener.onViewDetachedFromWindow(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishInflate() {
|
||||
|
||||
mImageButton = (ImageButton) findViewById(R.id.abs__imageButton);
|
||||
mTextButton = (CapitalizingButton) findViewById(R.id.abs__textButton);
|
||||
mImageButton.setOnClickListener(this);
|
||||
mTextButton.setOnClickListener(this);
|
||||
mImageButton.setOnLongClickListener(this);
|
||||
setOnClickListener(this);
|
||||
setOnLongClickListener(this);
|
||||
}
|
||||
|
||||
public MenuItemImpl getItemData() {
|
||||
return mItemData;
|
||||
}
|
||||
|
||||
public void initialize(MenuItemImpl itemData, int menuType) {
|
||||
mItemData = itemData;
|
||||
|
||||
setIcon(itemData.getIcon());
|
||||
setTitle(itemData.getTitleForItemView(this)); // Title only takes effect if there is no icon
|
||||
setId(itemData.getItemId());
|
||||
|
||||
setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE);
|
||||
setEnabled(itemData.isEnabled());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
super.setEnabled(enabled);
|
||||
mImageButton.setEnabled(enabled);
|
||||
mTextButton.setEnabled(enabled);
|
||||
}
|
||||
|
||||
public void onClick(View v) {
|
||||
if (mItemInvoker != null) {
|
||||
mItemInvoker.invokeItem(mItemData);
|
||||
}
|
||||
}
|
||||
|
||||
public void setItemInvoker(MenuBuilder.ItemInvoker invoker) {
|
||||
mItemInvoker = invoker;
|
||||
}
|
||||
|
||||
public boolean prefersCondensedTitle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setCheckable(boolean checkable) {
|
||||
// TODO Support checkable action items
|
||||
}
|
||||
|
||||
public void setChecked(boolean checked) {
|
||||
// TODO Support checkable action items
|
||||
}
|
||||
|
||||
public void setExpandedFormat(boolean expandedFormat) {
|
||||
if (mExpandedFormat != expandedFormat) {
|
||||
mExpandedFormat = expandedFormat;
|
||||
if (mItemData != null) {
|
||||
mItemData.actionFormatChanged();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTextButtonVisibility() {
|
||||
boolean visible = !TextUtils.isEmpty(mTextButton.getText());
|
||||
visible &= mImageButton.getDrawable() == null ||
|
||||
(mItemData.showsTextAsAction() && (mAllowTextWithIcon || mExpandedFormat));
|
||||
|
||||
mTextButton.setVisibility(visible ? VISIBLE : GONE);
|
||||
}
|
||||
|
||||
public void setIcon(Drawable icon) {
|
||||
mImageButton.setImageDrawable(icon);
|
||||
if (icon != null) {
|
||||
mImageButton.setVisibility(VISIBLE);
|
||||
} else {
|
||||
mImageButton.setVisibility(GONE);
|
||||
}
|
||||
|
||||
updateTextButtonVisibility();
|
||||
}
|
||||
|
||||
public boolean hasText() {
|
||||
return mTextButton.getVisibility() != GONE;
|
||||
}
|
||||
|
||||
public void setShortcut(boolean showShortcut, char shortcutKey) {
|
||||
// Action buttons don't show text for shortcut keys.
|
||||
}
|
||||
|
||||
public void setTitle(CharSequence title) {
|
||||
mTitle = title;
|
||||
|
||||
mTextButton.setTextCompat(mTitle);
|
||||
|
||||
setContentDescription(mTitle);
|
||||
updateTextButtonVisibility();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
|
||||
onPopulateAccessibilityEvent(event);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPopulateAccessibilityEvent(AccessibilityEvent event) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
super.onPopulateAccessibilityEvent(event);
|
||||
}
|
||||
final CharSequence cdesc = getContentDescription();
|
||||
if (!TextUtils.isEmpty(cdesc)) {
|
||||
event.getText().add(cdesc);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean dispatchHoverEvent(MotionEvent event) {
|
||||
// Don't allow children to hover; we want this to be treated as a single component.
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
return onHoverEvent(event);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean showsIcon() {
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean needsDividerBefore() {
|
||||
return hasText() && mItemData.getIcon() == null;
|
||||
}
|
||||
|
||||
public boolean needsDividerAfter() {
|
||||
return hasText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onLongClick(View v) {
|
||||
if (hasText()) {
|
||||
// Don't show the cheat sheet for items that already show text.
|
||||
return false;
|
||||
}
|
||||
|
||||
final int[] screenPos = new int[2];
|
||||
final Rect displayFrame = new Rect();
|
||||
getLocationOnScreen(screenPos);
|
||||
getWindowVisibleDisplayFrame(displayFrame);
|
||||
|
||||
final Context context = getContext();
|
||||
final int width = getWidth();
|
||||
final int height = getHeight();
|
||||
final int midy = screenPos[1] + height / 2;
|
||||
final int screenWidth = context.getResources().getDisplayMetrics().widthPixels;
|
||||
|
||||
Toast cheatSheet = IcsToast.makeText(context, mItemData.getTitle(), IcsToast.LENGTH_SHORT);
|
||||
if (midy < displayFrame.height()) {
|
||||
// Show along the top; follow action buttons
|
||||
cheatSheet.setGravity(Gravity.TOP | Gravity.RIGHT,
|
||||
screenWidth - screenPos[0] - width / 2, height);
|
||||
} else {
|
||||
// Show along the bottom center
|
||||
cheatSheet.setGravity(Gravity.BOTTOM | Gravity.CENTER_HORIZONTAL, 0, height);
|
||||
}
|
||||
cheatSheet.show();
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
|
||||
final int specSize = MeasureSpec.getSize(widthMeasureSpec);
|
||||
final int oldMeasuredWidth = getMeasuredWidth();
|
||||
final int targetWidth = widthMode == MeasureSpec.AT_MOST ? Math.min(specSize, mMinWidth)
|
||||
: mMinWidth;
|
||||
|
||||
if (widthMode != MeasureSpec.EXACTLY && mMinWidth > 0 && oldMeasuredWidth < targetWidth) {
|
||||
// Remeasure at exactly the minimum width.
|
||||
super.onMeasure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY),
|
||||
heightMeasureSpec);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,714 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.Resources;
|
||||
import android.os.Build;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.SparseBooleanArray;
|
||||
import android.view.SoundEffectConstants;
|
||||
import android.view.View;
|
||||
import android.view.View.MeasureSpec;
|
||||
import android.view.ViewConfiguration;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageButton;
|
||||
import com.actionbarsherlock.R;
|
||||
import com.actionbarsherlock.internal.view.View_HasStateListenerSupport;
|
||||
import com.actionbarsherlock.internal.view.View_OnAttachStateChangeListener;
|
||||
import com.actionbarsherlock.internal.view.menu.ActionMenuView.ActionMenuChildView;
|
||||
import com.actionbarsherlock.view.ActionProvider;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
/**
|
||||
* MenuPresenter for building action menus as seen in the action bar and action modes.
|
||||
*/
|
||||
public class ActionMenuPresenter extends BaseMenuPresenter
|
||||
implements ActionProvider.SubUiVisibilityListener {
|
||||
//UNUSED private static final String TAG = "ActionMenuPresenter";
|
||||
|
||||
private View mOverflowButton;
|
||||
private boolean mReserveOverflow;
|
||||
private boolean mReserveOverflowSet;
|
||||
private int mWidthLimit;
|
||||
private int mActionItemWidthLimit;
|
||||
private int mMaxItems;
|
||||
private boolean mMaxItemsSet;
|
||||
private boolean mStrictWidthLimit;
|
||||
private boolean mWidthLimitSet;
|
||||
private boolean mExpandedActionViewsExclusive;
|
||||
|
||||
private int mMinCellSize;
|
||||
|
||||
// Group IDs that have been added as actions - used temporarily, allocated here for reuse.
|
||||
private final SparseBooleanArray mActionButtonGroups = new SparseBooleanArray();
|
||||
|
||||
private View mScrapActionButtonView;
|
||||
|
||||
private OverflowPopup mOverflowPopup;
|
||||
private ActionButtonSubmenu mActionButtonPopup;
|
||||
|
||||
private OpenOverflowRunnable mPostedOpenRunnable;
|
||||
|
||||
final PopupPresenterCallback mPopupPresenterCallback = new PopupPresenterCallback();
|
||||
int mOpenSubMenuId;
|
||||
|
||||
public ActionMenuPresenter(Context context) {
|
||||
super(context, R.layout.abs__action_menu_layout,
|
||||
R.layout.abs__action_menu_item_layout);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initForMenu(Context context, MenuBuilder menu) {
|
||||
super.initForMenu(context, menu);
|
||||
|
||||
final Resources res = context.getResources();
|
||||
|
||||
if (!mReserveOverflowSet) {
|
||||
mReserveOverflow = reserveOverflow(mContext);
|
||||
}
|
||||
|
||||
if (!mWidthLimitSet) {
|
||||
mWidthLimit = res.getDisplayMetrics().widthPixels / 2;
|
||||
}
|
||||
|
||||
// Measure for initial configuration
|
||||
if (!mMaxItemsSet) {
|
||||
mMaxItems = getResources_getInteger(context, R.integer.abs__max_action_buttons);
|
||||
}
|
||||
|
||||
int width = mWidthLimit;
|
||||
if (mReserveOverflow) {
|
||||
if (mOverflowButton == null) {
|
||||
mOverflowButton = new OverflowMenuButton(mSystemContext);
|
||||
final int spec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
mOverflowButton.measure(spec, spec);
|
||||
}
|
||||
width -= mOverflowButton.getMeasuredWidth();
|
||||
} else {
|
||||
mOverflowButton = null;
|
||||
}
|
||||
|
||||
mActionItemWidthLimit = width;
|
||||
|
||||
mMinCellSize = (int) (ActionMenuView.MIN_CELL_SIZE * res.getDisplayMetrics().density);
|
||||
|
||||
// Drop a scrap view as it may no longer reflect the proper context/config.
|
||||
mScrapActionButtonView = null;
|
||||
}
|
||||
|
||||
public static boolean reserveOverflow(Context context) {
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
return (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB);
|
||||
} else {
|
||||
return !HasPermanentMenuKey.get(context);
|
||||
}
|
||||
}
|
||||
|
||||
private static class HasPermanentMenuKey {
|
||||
public static boolean get(Context context) {
|
||||
return ViewConfiguration.get(context).hasPermanentMenuKey();
|
||||
}
|
||||
}
|
||||
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
if (!mMaxItemsSet) {
|
||||
mMaxItems = getResources_getInteger(mContext,
|
||||
R.integer.abs__max_action_buttons);
|
||||
if (mMenu != null) {
|
||||
mMenu.onItemsChanged(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setWidthLimit(int width, boolean strict) {
|
||||
mWidthLimit = width;
|
||||
mStrictWidthLimit = strict;
|
||||
mWidthLimitSet = true;
|
||||
}
|
||||
|
||||
public void setReserveOverflow(boolean reserveOverflow) {
|
||||
mReserveOverflow = reserveOverflow;
|
||||
mReserveOverflowSet = true;
|
||||
}
|
||||
|
||||
public void setItemLimit(int itemCount) {
|
||||
mMaxItems = itemCount;
|
||||
mMaxItemsSet = true;
|
||||
}
|
||||
|
||||
public void setExpandedActionViewsExclusive(boolean isExclusive) {
|
||||
mExpandedActionViewsExclusive = isExclusive;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuView getMenuView(ViewGroup root) {
|
||||
MenuView result = super.getMenuView(root);
|
||||
((ActionMenuView) result).setPresenter(this);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getItemView(MenuItemImpl item, View convertView, ViewGroup parent) {
|
||||
View actionView = item.getActionView();
|
||||
if (actionView == null || item.hasCollapsibleActionView()) {
|
||||
if (!(convertView instanceof ActionMenuItemView)) {
|
||||
convertView = null;
|
||||
}
|
||||
actionView = super.getItemView(item, convertView, parent);
|
||||
}
|
||||
actionView.setVisibility(item.isActionViewExpanded() ? View.GONE : View.VISIBLE);
|
||||
|
||||
final ActionMenuView menuParent = (ActionMenuView) parent;
|
||||
final ViewGroup.LayoutParams lp = actionView.getLayoutParams();
|
||||
if (!menuParent.checkLayoutParams(lp)) {
|
||||
actionView.setLayoutParams(menuParent.generateLayoutParams(lp));
|
||||
}
|
||||
return actionView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindItemView(MenuItemImpl item, MenuView.ItemView itemView) {
|
||||
itemView.initialize(item, 0);
|
||||
|
||||
final ActionMenuView menuView = (ActionMenuView) mMenuView;
|
||||
ActionMenuItemView actionItemView = (ActionMenuItemView) itemView;
|
||||
actionItemView.setItemInvoker(menuView);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldIncludeItem(int childIndex, MenuItemImpl item) {
|
||||
return item.isActionButton();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateMenuView(boolean cleared) {
|
||||
super.updateMenuView(cleared);
|
||||
|
||||
if (mMenu != null) {
|
||||
final ArrayList<MenuItemImpl> actionItems = mMenu.getActionItems();
|
||||
final int count = actionItems.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final ActionProvider provider = actionItems.get(i).getActionProvider();
|
||||
if (provider != null) {
|
||||
provider.setSubUiVisibilityListener(this);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final ArrayList<MenuItemImpl> nonActionItems = mMenu != null ?
|
||||
mMenu.getNonActionItems() : null;
|
||||
|
||||
boolean hasOverflow = false;
|
||||
if (mReserveOverflow && nonActionItems != null) {
|
||||
final int count = nonActionItems.size();
|
||||
if (count == 1) {
|
||||
hasOverflow = !nonActionItems.get(0).isActionViewExpanded();
|
||||
} else {
|
||||
hasOverflow = count > 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (hasOverflow) {
|
||||
if (mOverflowButton == null) {
|
||||
mOverflowButton = new OverflowMenuButton(mSystemContext);
|
||||
}
|
||||
ViewGroup parent = (ViewGroup) mOverflowButton.getParent();
|
||||
if (parent != mMenuView) {
|
||||
if (parent != null) {
|
||||
parent.removeView(mOverflowButton);
|
||||
}
|
||||
ActionMenuView menuView = (ActionMenuView) mMenuView;
|
||||
menuView.addView(mOverflowButton, menuView.generateOverflowButtonLayoutParams());
|
||||
}
|
||||
} else if (mOverflowButton != null && mOverflowButton.getParent() == mMenuView) {
|
||||
((ViewGroup) mMenuView).removeView(mOverflowButton);
|
||||
}
|
||||
|
||||
((ActionMenuView) mMenuView).setOverflowReserved(mReserveOverflow);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean filterLeftoverView(ViewGroup parent, int childIndex) {
|
||||
if (parent.getChildAt(childIndex) == mOverflowButton) return false;
|
||||
return super.filterLeftoverView(parent, childIndex);
|
||||
}
|
||||
|
||||
public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
|
||||
if (!subMenu.hasVisibleItems()) return false;
|
||||
|
||||
SubMenuBuilder topSubMenu = subMenu;
|
||||
while (topSubMenu.getParentMenu() != mMenu) {
|
||||
topSubMenu = (SubMenuBuilder) topSubMenu.getParentMenu();
|
||||
}
|
||||
View anchor = findViewForItem(topSubMenu.getItem());
|
||||
if (anchor == null) {
|
||||
if (mOverflowButton == null) return false;
|
||||
anchor = mOverflowButton;
|
||||
}
|
||||
|
||||
mOpenSubMenuId = subMenu.getItem().getItemId();
|
||||
mActionButtonPopup = new ActionButtonSubmenu(mContext, subMenu);
|
||||
mActionButtonPopup.setAnchorView(anchor);
|
||||
mActionButtonPopup.show();
|
||||
super.onSubMenuSelected(subMenu);
|
||||
return true;
|
||||
}
|
||||
|
||||
private View findViewForItem(MenuItem item) {
|
||||
final ViewGroup parent = (ViewGroup) mMenuView;
|
||||
if (parent == null) return null;
|
||||
|
||||
final int count = parent.getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = parent.getChildAt(i);
|
||||
if (child instanceof MenuView.ItemView &&
|
||||
((MenuView.ItemView) child).getItemData() == item) {
|
||||
return child;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Display the overflow menu if one is present.
|
||||
* @return true if the overflow menu was shown, false otherwise.
|
||||
*/
|
||||
public boolean showOverflowMenu() {
|
||||
if (mReserveOverflow && !isOverflowMenuShowing() && mMenu != null && mMenuView != null &&
|
||||
mPostedOpenRunnable == null && !mMenu.getNonActionItems().isEmpty()) {
|
||||
OverflowPopup popup = new OverflowPopup(mContext, mMenu, mOverflowButton, true);
|
||||
mPostedOpenRunnable = new OpenOverflowRunnable(popup);
|
||||
// Post this for later; we might still need a layout for the anchor to be right.
|
||||
((View) mMenuView).post(mPostedOpenRunnable);
|
||||
|
||||
// ActionMenuPresenter uses null as a callback argument here
|
||||
// to indicate overflow is opening.
|
||||
super.onSubMenuSelected(null);
|
||||
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Hide the overflow menu if it is currently showing.
|
||||
*
|
||||
* @return true if the overflow menu was hidden, false otherwise.
|
||||
*/
|
||||
public boolean hideOverflowMenu() {
|
||||
if (mPostedOpenRunnable != null && mMenuView != null) {
|
||||
((View) mMenuView).removeCallbacks(mPostedOpenRunnable);
|
||||
mPostedOpenRunnable = null;
|
||||
return true;
|
||||
}
|
||||
|
||||
MenuPopupHelper popup = mOverflowPopup;
|
||||
if (popup != null) {
|
||||
popup.dismiss();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismiss all popup menus - overflow and submenus.
|
||||
* @return true if popups were dismissed, false otherwise. (This can be because none were open.)
|
||||
*/
|
||||
public boolean dismissPopupMenus() {
|
||||
boolean result = hideOverflowMenu();
|
||||
result |= hideSubMenus();
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismiss all submenu popups.
|
||||
*
|
||||
* @return true if popups were dismissed, false otherwise. (This can be because none were open.)
|
||||
*/
|
||||
public boolean hideSubMenus() {
|
||||
if (mActionButtonPopup != null) {
|
||||
mActionButtonPopup.dismiss();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if the overflow menu is currently showing
|
||||
*/
|
||||
public boolean isOverflowMenuShowing() {
|
||||
return mOverflowPopup != null && mOverflowPopup.isShowing();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return true if space has been reserved in the action menu for an overflow item.
|
||||
*/
|
||||
public boolean isOverflowReserved() {
|
||||
return mReserveOverflow;
|
||||
}
|
||||
|
||||
public boolean flagActionItems() {
|
||||
final ArrayList<MenuItemImpl> visibleItems = mMenu.getVisibleItems();
|
||||
final int itemsSize = visibleItems.size();
|
||||
int maxActions = mMaxItems;
|
||||
int widthLimit = mActionItemWidthLimit;
|
||||
final int querySpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
final ViewGroup parent = (ViewGroup) mMenuView;
|
||||
|
||||
int requiredItems = 0;
|
||||
int requestedItems = 0;
|
||||
int firstActionWidth = 0;
|
||||
boolean hasOverflow = false;
|
||||
for (int i = 0; i < itemsSize; i++) {
|
||||
MenuItemImpl item = visibleItems.get(i);
|
||||
if (item.requiresActionButton()) {
|
||||
requiredItems++;
|
||||
} else if (item.requestsActionButton()) {
|
||||
requestedItems++;
|
||||
} else {
|
||||
hasOverflow = true;
|
||||
}
|
||||
if (mExpandedActionViewsExclusive && item.isActionViewExpanded()) {
|
||||
// Overflow everything if we have an expanded action view and we're
|
||||
// space constrained.
|
||||
maxActions = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Reserve a spot for the overflow item if needed.
|
||||
if (mReserveOverflow &&
|
||||
(hasOverflow || requiredItems + requestedItems > maxActions)) {
|
||||
maxActions--;
|
||||
}
|
||||
maxActions -= requiredItems;
|
||||
|
||||
final SparseBooleanArray seenGroups = mActionButtonGroups;
|
||||
seenGroups.clear();
|
||||
|
||||
int cellSize = 0;
|
||||
int cellsRemaining = 0;
|
||||
if (mStrictWidthLimit) {
|
||||
cellsRemaining = widthLimit / mMinCellSize;
|
||||
final int cellSizeRemaining = widthLimit % mMinCellSize;
|
||||
cellSize = mMinCellSize + cellSizeRemaining / cellsRemaining;
|
||||
}
|
||||
|
||||
// Flag as many more requested items as will fit.
|
||||
for (int i = 0; i < itemsSize; i++) {
|
||||
MenuItemImpl item = visibleItems.get(i);
|
||||
|
||||
if (item.requiresActionButton()) {
|
||||
View v = getItemView(item, mScrapActionButtonView, parent);
|
||||
if (mScrapActionButtonView == null) {
|
||||
mScrapActionButtonView = v;
|
||||
}
|
||||
if (mStrictWidthLimit) {
|
||||
cellsRemaining -= ActionMenuView.measureChildForCells(v,
|
||||
cellSize, cellsRemaining, querySpec, 0);
|
||||
} else {
|
||||
v.measure(querySpec, querySpec);
|
||||
}
|
||||
final int measuredWidth = v.getMeasuredWidth();
|
||||
widthLimit -= measuredWidth;
|
||||
if (firstActionWidth == 0) {
|
||||
firstActionWidth = measuredWidth;
|
||||
}
|
||||
final int groupId = item.getGroupId();
|
||||
if (groupId != 0) {
|
||||
seenGroups.put(groupId, true);
|
||||
}
|
||||
item.setIsActionButton(true);
|
||||
} else if (item.requestsActionButton()) {
|
||||
// Items in a group with other items that already have an action slot
|
||||
// can break the max actions rule, but not the width limit.
|
||||
final int groupId = item.getGroupId();
|
||||
final boolean inGroup = seenGroups.get(groupId);
|
||||
boolean isAction = (maxActions > 0 || inGroup) && widthLimit > 0 &&
|
||||
(!mStrictWidthLimit || cellsRemaining > 0);
|
||||
|
||||
if (isAction) {
|
||||
View v = getItemView(item, mScrapActionButtonView, parent);
|
||||
if (mScrapActionButtonView == null) {
|
||||
mScrapActionButtonView = v;
|
||||
}
|
||||
if (mStrictWidthLimit) {
|
||||
final int cells = ActionMenuView.measureChildForCells(v,
|
||||
cellSize, cellsRemaining, querySpec, 0);
|
||||
cellsRemaining -= cells;
|
||||
if (cells == 0) {
|
||||
isAction = false;
|
||||
}
|
||||
} else {
|
||||
v.measure(querySpec, querySpec);
|
||||
}
|
||||
final int measuredWidth = v.getMeasuredWidth();
|
||||
widthLimit -= measuredWidth;
|
||||
if (firstActionWidth == 0) {
|
||||
firstActionWidth = measuredWidth;
|
||||
}
|
||||
|
||||
if (mStrictWidthLimit) {
|
||||
isAction &= widthLimit >= 0;
|
||||
} else {
|
||||
// Did this push the entire first item past the limit?
|
||||
isAction &= widthLimit + firstActionWidth > 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (isAction && groupId != 0) {
|
||||
seenGroups.put(groupId, true);
|
||||
} else if (inGroup) {
|
||||
// We broke the width limit. Demote the whole group, they all overflow now.
|
||||
seenGroups.put(groupId, false);
|
||||
for (int j = 0; j < i; j++) {
|
||||
MenuItemImpl areYouMyGroupie = visibleItems.get(j);
|
||||
if (areYouMyGroupie.getGroupId() == groupId) {
|
||||
// Give back the action slot
|
||||
if (areYouMyGroupie.isActionButton()) maxActions++;
|
||||
areYouMyGroupie.setIsActionButton(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isAction) maxActions--;
|
||||
|
||||
item.setIsActionButton(isAction);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
|
||||
dismissPopupMenus();
|
||||
super.onCloseMenu(menu, allMenusAreClosing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parcelable onSaveInstanceState() {
|
||||
SavedState state = new SavedState();
|
||||
state.openSubMenuId = mOpenSubMenuId;
|
||||
return state;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreInstanceState(Parcelable state) {
|
||||
SavedState saved = (SavedState) state;
|
||||
if (saved.openSubMenuId > 0) {
|
||||
MenuItem item = mMenu.findItem(saved.openSubMenuId);
|
||||
if (item != null) {
|
||||
SubMenuBuilder subMenu = (SubMenuBuilder) item.getSubMenu();
|
||||
onSubMenuSelected(subMenu);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onSubUiVisibilityChanged(boolean isVisible) {
|
||||
if (isVisible) {
|
||||
// Not a submenu, but treat it like one.
|
||||
super.onSubMenuSelected(null);
|
||||
} else {
|
||||
mMenu.close(false);
|
||||
}
|
||||
}
|
||||
|
||||
private static class SavedState implements Parcelable {
|
||||
public int openSubMenuId;
|
||||
|
||||
SavedState() {
|
||||
}
|
||||
|
||||
SavedState(Parcel in) {
|
||||
openSubMenuId = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel dest, int flags) {
|
||||
dest.writeInt(openSubMenuId);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static final Parcelable.Creator<SavedState> CREATOR
|
||||
= new Parcelable.Creator<SavedState>() {
|
||||
public SavedState createFromParcel(Parcel in) {
|
||||
return new SavedState(in);
|
||||
}
|
||||
|
||||
public SavedState[] newArray(int size) {
|
||||
return new SavedState[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private class OverflowMenuButton extends ImageButton implements ActionMenuChildView, View_HasStateListenerSupport {
|
||||
private final Set<View_OnAttachStateChangeListener> mListeners = new HashSet<View_OnAttachStateChangeListener>();
|
||||
|
||||
public OverflowMenuButton(Context context) {
|
||||
super(context, null, R.attr.actionOverflowButtonStyle);
|
||||
|
||||
setClickable(true);
|
||||
setFocusable(true);
|
||||
setVisibility(VISIBLE);
|
||||
setEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performClick() {
|
||||
if (super.performClick()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
playSoundEffect(SoundEffectConstants.CLICK);
|
||||
showOverflowMenu();
|
||||
return true;
|
||||
}
|
||||
|
||||
public boolean needsDividerBefore() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean needsDividerAfter() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
for (View_OnAttachStateChangeListener listener : mListeners) {
|
||||
listener.onViewAttachedToWindow(this);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
for (View_OnAttachStateChangeListener listener : mListeners) {
|
||||
listener.onViewDetachedFromWindow(this);
|
||||
}
|
||||
|
||||
if (mOverflowPopup != null) mOverflowPopup.dismiss();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addOnAttachStateChangeListener(View_OnAttachStateChangeListener listener) {
|
||||
mListeners.add(listener);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeOnAttachStateChangeListener(View_OnAttachStateChangeListener listener) {
|
||||
mListeners.remove(listener);
|
||||
}
|
||||
}
|
||||
|
||||
private class OverflowPopup extends MenuPopupHelper {
|
||||
public OverflowPopup(Context context, MenuBuilder menu, View anchorView,
|
||||
boolean overflowOnly) {
|
||||
super(context, menu, anchorView, overflowOnly);
|
||||
setCallback(mPopupPresenterCallback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss() {
|
||||
super.onDismiss();
|
||||
mMenu.close();
|
||||
mOverflowPopup = null;
|
||||
}
|
||||
}
|
||||
|
||||
private class ActionButtonSubmenu extends MenuPopupHelper {
|
||||
//UNUSED private SubMenuBuilder mSubMenu;
|
||||
|
||||
public ActionButtonSubmenu(Context context, SubMenuBuilder subMenu) {
|
||||
super(context, subMenu);
|
||||
//UNUSED mSubMenu = subMenu;
|
||||
|
||||
MenuItemImpl item = (MenuItemImpl) subMenu.getItem();
|
||||
if (!item.isActionButton()) {
|
||||
// Give a reasonable anchor to nested submenus.
|
||||
setAnchorView(mOverflowButton == null ? (View) mMenuView : mOverflowButton);
|
||||
}
|
||||
|
||||
setCallback(mPopupPresenterCallback);
|
||||
|
||||
boolean preserveIconSpacing = false;
|
||||
final int count = subMenu.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
MenuItem childItem = subMenu.getItem(i);
|
||||
if (childItem.isVisible() && childItem.getIcon() != null) {
|
||||
preserveIconSpacing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
setForceShowIcon(preserveIconSpacing);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDismiss() {
|
||||
super.onDismiss();
|
||||
mActionButtonPopup = null;
|
||||
mOpenSubMenuId = 0;
|
||||
}
|
||||
}
|
||||
|
||||
private class PopupPresenterCallback implements MenuPresenter.Callback {
|
||||
|
||||
@Override
|
||||
public boolean onOpenSubMenu(MenuBuilder subMenu) {
|
||||
if (subMenu == null) return false;
|
||||
|
||||
mOpenSubMenuId = ((SubMenuBuilder) subMenu).getItem().getItemId();
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
|
||||
if (menu instanceof SubMenuBuilder) {
|
||||
((SubMenuBuilder) menu).getRootMenu().close(false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class OpenOverflowRunnable implements Runnable {
|
||||
private OverflowPopup mPopup;
|
||||
|
||||
public OpenOverflowRunnable(OverflowPopup popup) {
|
||||
mPopup = popup;
|
||||
}
|
||||
|
||||
public void run() {
|
||||
mMenu.changeMenuMode();
|
||||
final View menuView = (View) mMenuView;
|
||||
if (menuView != null && menuView.getWindowToken() != null && mPopup.tryShow()) {
|
||||
mOverflowPopup = mPopup;
|
||||
}
|
||||
mPostedOpenRunnable = null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,575 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.graphics.Canvas;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.widget.LinearLayout;
|
||||
import com.actionbarsherlock.internal.widget.IcsLinearLayout;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ActionMenuView extends IcsLinearLayout implements MenuBuilder.ItemInvoker, MenuView {
|
||||
//UNUSED private static final String TAG = "ActionMenuView";
|
||||
private static final boolean IS_FROYO = Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO;
|
||||
|
||||
static final int MIN_CELL_SIZE = 56; // dips
|
||||
static final int GENERATED_ITEM_PADDING = 4; // dips
|
||||
|
||||
private MenuBuilder mMenu;
|
||||
|
||||
private boolean mReserveOverflow;
|
||||
private ActionMenuPresenter mPresenter;
|
||||
private boolean mFormatItems;
|
||||
private int mFormatItemsWidth;
|
||||
private int mMinCellSize;
|
||||
private int mGeneratedItemPadding;
|
||||
//UNUSED private int mMeasuredExtraWidth;
|
||||
|
||||
private boolean mFirst = true;
|
||||
|
||||
public ActionMenuView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public ActionMenuView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
setBaselineAligned(false);
|
||||
final float density = context.getResources().getDisplayMetrics().density;
|
||||
mMinCellSize = (int) (MIN_CELL_SIZE * density);
|
||||
mGeneratedItemPadding = (int) (GENERATED_ITEM_PADDING * density);
|
||||
}
|
||||
|
||||
public void setPresenter(ActionMenuPresenter presenter) {
|
||||
mPresenter = presenter;
|
||||
}
|
||||
|
||||
public boolean isExpandedFormat() {
|
||||
return mFormatItems;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
if (IS_FROYO) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
}
|
||||
mPresenter.updateMenuView(false);
|
||||
|
||||
if (mPresenter != null && mPresenter.isOverflowMenuShowing()) {
|
||||
mPresenter.hideOverflowMenu();
|
||||
mPresenter.showOverflowMenu();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
//Need to trigger a relayout since we may have been added extremely
|
||||
//late in the initial rendering (e.g., when contained in a ViewPager).
|
||||
//See: https://github.com/JakeWharton/ActionBarSherlock/issues/272
|
||||
if (!IS_FROYO && mFirst) {
|
||||
mFirst = false;
|
||||
requestLayout();
|
||||
return;
|
||||
}
|
||||
super.onDraw(canvas);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
// If we've been given an exact size to match, apply special formatting during layout.
|
||||
final boolean wasFormatted = mFormatItems;
|
||||
mFormatItems = MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.EXACTLY;
|
||||
|
||||
if (wasFormatted != mFormatItems) {
|
||||
mFormatItemsWidth = 0; // Reset this when switching modes
|
||||
}
|
||||
|
||||
// Special formatting can change whether items can fit as action buttons.
|
||||
// Kick the menu and update presenters when this changes.
|
||||
final int widthSize = MeasureSpec.getMode(widthMeasureSpec);
|
||||
if (mFormatItems && mMenu != null && widthSize != mFormatItemsWidth) {
|
||||
mFormatItemsWidth = widthSize;
|
||||
mMenu.onItemsChanged(true);
|
||||
}
|
||||
|
||||
if (mFormatItems) {
|
||||
onMeasureExactFormat(widthMeasureSpec, heightMeasureSpec);
|
||||
} else {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
}
|
||||
|
||||
private void onMeasureExactFormat(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
// We already know the width mode is EXACTLY if we're here.
|
||||
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
|
||||
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
|
||||
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
|
||||
|
||||
final int widthPadding = getPaddingLeft() + getPaddingRight();
|
||||
final int heightPadding = getPaddingTop() + getPaddingBottom();
|
||||
|
||||
widthSize -= widthPadding;
|
||||
|
||||
// Divide the view into cells.
|
||||
final int cellCount = widthSize / mMinCellSize;
|
||||
final int cellSizeRemaining = widthSize % mMinCellSize;
|
||||
|
||||
if (cellCount == 0) {
|
||||
// Give up, nothing fits.
|
||||
setMeasuredDimension(widthSize, 0);
|
||||
return;
|
||||
}
|
||||
|
||||
final int cellSize = mMinCellSize + cellSizeRemaining / cellCount;
|
||||
|
||||
int cellsRemaining = cellCount;
|
||||
int maxChildHeight = 0;
|
||||
int maxCellsUsed = 0;
|
||||
int expandableItemCount = 0;
|
||||
int visibleItemCount = 0;
|
||||
boolean hasOverflow = false;
|
||||
|
||||
// This is used as a bitfield to locate the smallest items present. Assumes childCount < 64.
|
||||
long smallestItemsAt = 0;
|
||||
|
||||
final int childCount = getChildCount();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = getChildAt(i);
|
||||
if (child.getVisibility() == GONE) continue;
|
||||
|
||||
final boolean isGeneratedItem = child instanceof ActionMenuItemView;
|
||||
visibleItemCount++;
|
||||
|
||||
if (isGeneratedItem) {
|
||||
// Reset padding for generated menu item views; it may change below
|
||||
// and views are recycled.
|
||||
child.setPadding(mGeneratedItemPadding, 0, mGeneratedItemPadding, 0);
|
||||
}
|
||||
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
lp.expanded = false;
|
||||
lp.extraPixels = 0;
|
||||
lp.cellsUsed = 0;
|
||||
lp.expandable = false;
|
||||
lp.leftMargin = 0;
|
||||
lp.rightMargin = 0;
|
||||
lp.preventEdgeOffset = isGeneratedItem && ((ActionMenuItemView) child).hasText();
|
||||
|
||||
// Overflow always gets 1 cell. No more, no less.
|
||||
final int cellsAvailable = lp.isOverflowButton ? 1 : cellsRemaining;
|
||||
|
||||
final int cellsUsed = measureChildForCells(child, cellSize, cellsAvailable,
|
||||
heightMeasureSpec, heightPadding);
|
||||
|
||||
maxCellsUsed = Math.max(maxCellsUsed, cellsUsed);
|
||||
if (lp.expandable) expandableItemCount++;
|
||||
if (lp.isOverflowButton) hasOverflow = true;
|
||||
|
||||
cellsRemaining -= cellsUsed;
|
||||
maxChildHeight = Math.max(maxChildHeight, child.getMeasuredHeight());
|
||||
if (cellsUsed == 1) smallestItemsAt |= (1 << i);
|
||||
}
|
||||
|
||||
// When we have overflow and a single expanded (text) item, we want to try centering it
|
||||
// visually in the available space even though overflow consumes some of it.
|
||||
final boolean centerSingleExpandedItem = hasOverflow && visibleItemCount == 2;
|
||||
|
||||
// Divide space for remaining cells if we have items that can expand.
|
||||
// Try distributing whole leftover cells to smaller items first.
|
||||
|
||||
boolean needsExpansion = false;
|
||||
while (expandableItemCount > 0 && cellsRemaining > 0) {
|
||||
int minCells = Integer.MAX_VALUE;
|
||||
long minCellsAt = 0; // Bit locations are indices of relevant child views
|
||||
int minCellsItemCount = 0;
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = getChildAt(i);
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
|
||||
// Don't try to expand items that shouldn't.
|
||||
if (!lp.expandable) continue;
|
||||
|
||||
// Mark indices of children that can receive an extra cell.
|
||||
if (lp.cellsUsed < minCells) {
|
||||
minCells = lp.cellsUsed;
|
||||
minCellsAt = 1 << i;
|
||||
minCellsItemCount = 1;
|
||||
} else if (lp.cellsUsed == minCells) {
|
||||
minCellsAt |= 1 << i;
|
||||
minCellsItemCount++;
|
||||
}
|
||||
}
|
||||
|
||||
// Items that get expanded will always be in the set of smallest items when we're done.
|
||||
smallestItemsAt |= minCellsAt;
|
||||
|
||||
if (minCellsItemCount > cellsRemaining) break; // Couldn't expand anything evenly. Stop.
|
||||
|
||||
// We have enough cells, all minimum size items will be incremented.
|
||||
minCells++;
|
||||
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = getChildAt(i);
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
if ((minCellsAt & (1 << i)) == 0) {
|
||||
// If this item is already at our small item count, mark it for later.
|
||||
if (lp.cellsUsed == minCells) smallestItemsAt |= 1 << i;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (centerSingleExpandedItem && lp.preventEdgeOffset && cellsRemaining == 1) {
|
||||
// Add padding to this item such that it centers.
|
||||
child.setPadding(mGeneratedItemPadding + cellSize, 0, mGeneratedItemPadding, 0);
|
||||
}
|
||||
lp.cellsUsed++;
|
||||
lp.expanded = true;
|
||||
cellsRemaining--;
|
||||
}
|
||||
|
||||
needsExpansion = true;
|
||||
}
|
||||
|
||||
// Divide any space left that wouldn't divide along cell boundaries
|
||||
// evenly among the smallest items
|
||||
|
||||
final boolean singleItem = !hasOverflow && visibleItemCount == 1;
|
||||
if (cellsRemaining > 0 && smallestItemsAt != 0 &&
|
||||
(cellsRemaining < visibleItemCount - 1 || singleItem || maxCellsUsed > 1)) {
|
||||
float expandCount = Long.bitCount(smallestItemsAt);
|
||||
|
||||
if (!singleItem) {
|
||||
// The items at the far edges may only expand by half in order to pin to either side.
|
||||
if ((smallestItemsAt & 1) != 0) {
|
||||
LayoutParams lp = (LayoutParams) getChildAt(0).getLayoutParams();
|
||||
if (!lp.preventEdgeOffset) expandCount -= 0.5f;
|
||||
}
|
||||
if ((smallestItemsAt & (1 << (childCount - 1))) != 0) {
|
||||
LayoutParams lp = ((LayoutParams) getChildAt(childCount - 1).getLayoutParams());
|
||||
if (!lp.preventEdgeOffset) expandCount -= 0.5f;
|
||||
}
|
||||
}
|
||||
|
||||
final int extraPixels = expandCount > 0 ?
|
||||
(int) (cellsRemaining * cellSize / expandCount) : 0;
|
||||
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
if ((smallestItemsAt & (1 << i)) == 0) continue;
|
||||
|
||||
final View child = getChildAt(i);
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
if (child instanceof ActionMenuItemView) {
|
||||
// If this is one of our views, expand and measure at the larger size.
|
||||
lp.extraPixels = extraPixels;
|
||||
lp.expanded = true;
|
||||
if (i == 0 && !lp.preventEdgeOffset) {
|
||||
// First item gets part of its new padding pushed out of sight.
|
||||
// The last item will get this implicitly from layout.
|
||||
lp.leftMargin = -extraPixels / 2;
|
||||
}
|
||||
needsExpansion = true;
|
||||
} else if (lp.isOverflowButton) {
|
||||
lp.extraPixels = extraPixels;
|
||||
lp.expanded = true;
|
||||
lp.rightMargin = -extraPixels / 2;
|
||||
needsExpansion = true;
|
||||
} else {
|
||||
// If we don't know what it is, give it some margins instead
|
||||
// and let it center within its space. We still want to pin
|
||||
// against the edges.
|
||||
if (i != 0) {
|
||||
lp.leftMargin = extraPixels / 2;
|
||||
}
|
||||
if (i != childCount - 1) {
|
||||
lp.rightMargin = extraPixels / 2;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
cellsRemaining = 0;
|
||||
}
|
||||
|
||||
// Remeasure any items that have had extra space allocated to them.
|
||||
if (needsExpansion) {
|
||||
int heightSpec = MeasureSpec.makeMeasureSpec(heightSize - heightPadding, heightMode);
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = getChildAt(i);
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
|
||||
if (!lp.expanded) continue;
|
||||
|
||||
final int width = lp.cellsUsed * cellSize + lp.extraPixels;
|
||||
child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY), heightSpec);
|
||||
}
|
||||
}
|
||||
|
||||
if (heightMode != MeasureSpec.EXACTLY) {
|
||||
heightSize = maxChildHeight;
|
||||
}
|
||||
|
||||
setMeasuredDimension(widthSize, heightSize);
|
||||
//UNUSED mMeasuredExtraWidth = cellsRemaining * cellSize;
|
||||
}
|
||||
|
||||
/**
|
||||
* Measure a child view to fit within cell-based formatting. The child's width
|
||||
* will be measured to a whole multiple of cellSize.
|
||||
*
|
||||
* <p>Sets the expandable and cellsUsed fields of LayoutParams.
|
||||
*
|
||||
* @param child Child to measure
|
||||
* @param cellSize Size of one cell
|
||||
* @param cellsRemaining Number of cells remaining that this view can expand to fill
|
||||
* @param parentHeightMeasureSpec MeasureSpec used by the parent view
|
||||
* @param parentHeightPadding Padding present in the parent view
|
||||
* @return Number of cells this child was measured to occupy
|
||||
*/
|
||||
static int measureChildForCells(View child, int cellSize, int cellsRemaining,
|
||||
int parentHeightMeasureSpec, int parentHeightPadding) {
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
|
||||
final int childHeightSize = MeasureSpec.getSize(parentHeightMeasureSpec) -
|
||||
parentHeightPadding;
|
||||
final int childHeightMode = MeasureSpec.getMode(parentHeightMeasureSpec);
|
||||
final int childHeightSpec = MeasureSpec.makeMeasureSpec(childHeightSize, childHeightMode);
|
||||
|
||||
int cellsUsed = 0;
|
||||
if (cellsRemaining > 0) {
|
||||
final int childWidthSpec = MeasureSpec.makeMeasureSpec(
|
||||
cellSize * cellsRemaining, MeasureSpec.AT_MOST);
|
||||
child.measure(childWidthSpec, childHeightSpec);
|
||||
|
||||
final int measuredWidth = child.getMeasuredWidth();
|
||||
cellsUsed = measuredWidth / cellSize;
|
||||
if (measuredWidth % cellSize != 0) cellsUsed++;
|
||||
}
|
||||
|
||||
final ActionMenuItemView itemView = child instanceof ActionMenuItemView ?
|
||||
(ActionMenuItemView) child : null;
|
||||
final boolean expandable = !lp.isOverflowButton && itemView != null && itemView.hasText();
|
||||
lp.expandable = expandable;
|
||||
|
||||
lp.cellsUsed = cellsUsed;
|
||||
final int targetWidth = cellsUsed * cellSize;
|
||||
child.measure(MeasureSpec.makeMeasureSpec(targetWidth, MeasureSpec.EXACTLY),
|
||||
childHeightSpec);
|
||||
return cellsUsed;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
if (!mFormatItems) {
|
||||
super.onLayout(changed, left, top, right, bottom);
|
||||
return;
|
||||
}
|
||||
|
||||
final int childCount = getChildCount();
|
||||
final int midVertical = (top + bottom) / 2;
|
||||
final int dividerWidth = 0;//getDividerWidth();
|
||||
int overflowWidth = 0;
|
||||
//UNUSED int nonOverflowWidth = 0;
|
||||
int nonOverflowCount = 0;
|
||||
int widthRemaining = right - left - getPaddingRight() - getPaddingLeft();
|
||||
boolean hasOverflow = false;
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View v = getChildAt(i);
|
||||
if (v.getVisibility() == GONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
LayoutParams p = (LayoutParams) v.getLayoutParams();
|
||||
if (p.isOverflowButton) {
|
||||
overflowWidth = v.getMeasuredWidth();
|
||||
if (hasDividerBeforeChildAt(i)) {
|
||||
overflowWidth += dividerWidth;
|
||||
}
|
||||
|
||||
int height = v.getMeasuredHeight();
|
||||
int r = getWidth() - getPaddingRight() - p.rightMargin;
|
||||
int l = r - overflowWidth;
|
||||
int t = midVertical - (height / 2);
|
||||
int b = t + height;
|
||||
v.layout(l, t, r, b);
|
||||
|
||||
widthRemaining -= overflowWidth;
|
||||
hasOverflow = true;
|
||||
} else {
|
||||
final int size = v.getMeasuredWidth() + p.leftMargin + p.rightMargin;
|
||||
//UNUSED nonOverflowWidth += size;
|
||||
widthRemaining -= size;
|
||||
//if (hasDividerBeforeChildAt(i)) {
|
||||
//UNUSED nonOverflowWidth += dividerWidth;
|
||||
//}
|
||||
nonOverflowCount++;
|
||||
}
|
||||
}
|
||||
|
||||
if (childCount == 1 && !hasOverflow) {
|
||||
// Center a single child
|
||||
final View v = getChildAt(0);
|
||||
final int width = v.getMeasuredWidth();
|
||||
final int height = v.getMeasuredHeight();
|
||||
final int midHorizontal = (right - left) / 2;
|
||||
final int l = midHorizontal - width / 2;
|
||||
final int t = midVertical - height / 2;
|
||||
v.layout(l, t, l + width, t + height);
|
||||
return;
|
||||
}
|
||||
|
||||
final int spacerCount = nonOverflowCount - (hasOverflow ? 0 : 1);
|
||||
final int spacerSize = Math.max(0, spacerCount > 0 ? widthRemaining / spacerCount : 0);
|
||||
|
||||
int startLeft = getPaddingLeft();
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View v = getChildAt(i);
|
||||
final LayoutParams lp = (LayoutParams) v.getLayoutParams();
|
||||
if (v.getVisibility() == GONE || lp.isOverflowButton) {
|
||||
continue;
|
||||
}
|
||||
|
||||
startLeft += lp.leftMargin;
|
||||
int width = v.getMeasuredWidth();
|
||||
int height = v.getMeasuredHeight();
|
||||
int t = midVertical - height / 2;
|
||||
v.layout(startLeft, t, startLeft + width, t + height);
|
||||
startLeft += width + lp.rightMargin + spacerSize;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
mPresenter.dismissPopupMenus();
|
||||
}
|
||||
|
||||
public boolean isOverflowReserved() {
|
||||
return mReserveOverflow;
|
||||
}
|
||||
|
||||
public void setOverflowReserved(boolean reserveOverflow) {
|
||||
mReserveOverflow = reserveOverflow;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LayoutParams generateDefaultLayoutParams() {
|
||||
LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT,
|
||||
LayoutParams.WRAP_CONTENT);
|
||||
params.gravity = Gravity.CENTER_VERTICAL;
|
||||
return params;
|
||||
}
|
||||
|
||||
@Override
|
||||
public LayoutParams generateLayoutParams(AttributeSet attrs) {
|
||||
return new LayoutParams(getContext(), attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
|
||||
if (p instanceof LayoutParams) {
|
||||
LayoutParams result = new LayoutParams((LayoutParams) p);
|
||||
if (result.gravity <= Gravity.NO_GRAVITY) {
|
||||
result.gravity = Gravity.CENTER_VERTICAL;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
return generateDefaultLayoutParams();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
|
||||
return p != null && p instanceof LayoutParams;
|
||||
}
|
||||
|
||||
public LayoutParams generateOverflowButtonLayoutParams() {
|
||||
LayoutParams result = generateDefaultLayoutParams();
|
||||
result.isOverflowButton = true;
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean invokeItem(MenuItemImpl item) {
|
||||
return mMenu.performItemAction(item, 0);
|
||||
}
|
||||
|
||||
public int getWindowAnimations() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void initialize(MenuBuilder menu) {
|
||||
mMenu = menu;
|
||||
}
|
||||
|
||||
//@Override
|
||||
protected boolean hasDividerBeforeChildAt(int childIndex) {
|
||||
if (childIndex == 0) {
|
||||
return false;
|
||||
}
|
||||
final View childBefore = getChildAt(childIndex - 1);
|
||||
final View child = getChildAt(childIndex);
|
||||
boolean result = false;
|
||||
if (childIndex < getChildCount() && childBefore instanceof ActionMenuChildView) {
|
||||
result |= ((ActionMenuChildView) childBefore).needsDividerAfter();
|
||||
}
|
||||
if (childIndex > 0 && child instanceof ActionMenuChildView) {
|
||||
result |= ((ActionMenuChildView) child).needsDividerBefore();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public boolean dispatchPopulateAccessibilityEvent(AccessibilityEvent event) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public interface ActionMenuChildView {
|
||||
public boolean needsDividerBefore();
|
||||
public boolean needsDividerAfter();
|
||||
}
|
||||
|
||||
public static class LayoutParams extends LinearLayout.LayoutParams {
|
||||
public boolean isOverflowButton;
|
||||
public int cellsUsed;
|
||||
public int extraPixels;
|
||||
public boolean expandable;
|
||||
public boolean preventEdgeOffset;
|
||||
|
||||
public boolean expanded;
|
||||
|
||||
public LayoutParams(Context c, AttributeSet attrs) {
|
||||
super(c, attrs);
|
||||
}
|
||||
|
||||
public LayoutParams(LayoutParams other) {
|
||||
super((LinearLayout.LayoutParams) other);
|
||||
isOverflowButton = other.isOverflowButton;
|
||||
}
|
||||
|
||||
public LayoutParams(int width, int height) {
|
||||
super(width, height);
|
||||
isOverflowButton = false;
|
||||
}
|
||||
|
||||
public LayoutParams(int width, int height, boolean isOverflowButton) {
|
||||
super(width, height);
|
||||
this.isOverflowButton = isOverflowButton;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,231 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* Base class for MenuPresenters that have a consistent container view and item
|
||||
* views. Behaves similarly to an AdapterView in that existing item views will
|
||||
* be reused if possible when items change.
|
||||
*/
|
||||
public abstract class BaseMenuPresenter implements MenuPresenter {
|
||||
private static final boolean IS_HONEYCOMB = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
|
||||
|
||||
protected Context mSystemContext;
|
||||
protected Context mContext;
|
||||
protected MenuBuilder mMenu;
|
||||
protected LayoutInflater mSystemInflater;
|
||||
protected LayoutInflater mInflater;
|
||||
private Callback mCallback;
|
||||
|
||||
private int mMenuLayoutRes;
|
||||
private int mItemLayoutRes;
|
||||
|
||||
protected MenuView mMenuView;
|
||||
|
||||
private int mId;
|
||||
|
||||
/**
|
||||
* Construct a new BaseMenuPresenter.
|
||||
*
|
||||
* @param context Context for generating system-supplied views
|
||||
* @param menuLayoutRes Layout resource ID for the menu container view
|
||||
* @param itemLayoutRes Layout resource ID for a single item view
|
||||
*/
|
||||
public BaseMenuPresenter(Context context, int menuLayoutRes, int itemLayoutRes) {
|
||||
mSystemContext = context;
|
||||
mSystemInflater = LayoutInflater.from(context);
|
||||
mMenuLayoutRes = menuLayoutRes;
|
||||
mItemLayoutRes = itemLayoutRes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initForMenu(Context context, MenuBuilder menu) {
|
||||
mContext = context;
|
||||
mInflater = LayoutInflater.from(mContext);
|
||||
mMenu = menu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuView getMenuView(ViewGroup root) {
|
||||
if (mMenuView == null) {
|
||||
mMenuView = (MenuView) mSystemInflater.inflate(mMenuLayoutRes, root, false);
|
||||
mMenuView.initialize(mMenu);
|
||||
updateMenuView(true);
|
||||
}
|
||||
|
||||
return mMenuView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reuses item views when it can
|
||||
*/
|
||||
public void updateMenuView(boolean cleared) {
|
||||
final ViewGroup parent = (ViewGroup) mMenuView;
|
||||
if (parent == null) return;
|
||||
|
||||
int childIndex = 0;
|
||||
if (mMenu != null) {
|
||||
mMenu.flagActionItems();
|
||||
ArrayList<MenuItemImpl> visibleItems = mMenu.getVisibleItems();
|
||||
final int itemCount = visibleItems.size();
|
||||
for (int i = 0; i < itemCount; i++) {
|
||||
MenuItemImpl item = visibleItems.get(i);
|
||||
if (shouldIncludeItem(childIndex, item)) {
|
||||
final View convertView = parent.getChildAt(childIndex);
|
||||
final MenuItemImpl oldItem = convertView instanceof MenuView.ItemView ?
|
||||
((MenuView.ItemView) convertView).getItemData() : null;
|
||||
final View itemView = getItemView(item, convertView, parent);
|
||||
if (item != oldItem) {
|
||||
// Don't let old states linger with new data.
|
||||
itemView.setPressed(false);
|
||||
if (IS_HONEYCOMB) itemView.jumpDrawablesToCurrentState();
|
||||
}
|
||||
if (itemView != convertView) {
|
||||
addItemView(itemView, childIndex);
|
||||
}
|
||||
childIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove leftover views.
|
||||
while (childIndex < parent.getChildCount()) {
|
||||
if (!filterLeftoverView(parent, childIndex)) {
|
||||
childIndex++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an item view at the given index.
|
||||
*
|
||||
* @param itemView View to add
|
||||
* @param childIndex Index within the parent to insert at
|
||||
*/
|
||||
protected void addItemView(View itemView, int childIndex) {
|
||||
final ViewGroup currentParent = (ViewGroup) itemView.getParent();
|
||||
if (currentParent != null) {
|
||||
currentParent.removeView(itemView);
|
||||
}
|
||||
((ViewGroup) mMenuView).addView(itemView, childIndex);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the child view at index and remove it if appropriate.
|
||||
* @param parent Parent to filter from
|
||||
* @param childIndex Index to filter
|
||||
* @return true if the child view at index was removed
|
||||
*/
|
||||
protected boolean filterLeftoverView(ViewGroup parent, int childIndex) {
|
||||
parent.removeViewAt(childIndex);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setCallback(Callback cb) {
|
||||
mCallback = cb;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new item view that can be re-bound to other item data later.
|
||||
*
|
||||
* @return The new item view
|
||||
*/
|
||||
public MenuView.ItemView createItemView(ViewGroup parent) {
|
||||
return (MenuView.ItemView) mSystemInflater.inflate(mItemLayoutRes, parent, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepare an item view for use. See AdapterView for the basic idea at work here.
|
||||
* This may require creating a new item view, but well-behaved implementations will
|
||||
* re-use the view passed as convertView if present. The returned view will be populated
|
||||
* with data from the item parameter.
|
||||
*
|
||||
* @param item Item to present
|
||||
* @param convertView Existing view to reuse
|
||||
* @param parent Intended parent view - use for inflation.
|
||||
* @return View that presents the requested menu item
|
||||
*/
|
||||
public View getItemView(MenuItemImpl item, View convertView, ViewGroup parent) {
|
||||
MenuView.ItemView itemView;
|
||||
if (convertView instanceof MenuView.ItemView) {
|
||||
itemView = (MenuView.ItemView) convertView;
|
||||
} else {
|
||||
itemView = createItemView(parent);
|
||||
}
|
||||
bindItemView(item, itemView);
|
||||
return (View) itemView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Bind item data to an existing item view.
|
||||
*
|
||||
* @param item Item to bind
|
||||
* @param itemView View to populate with item data
|
||||
*/
|
||||
public abstract void bindItemView(MenuItemImpl item, MenuView.ItemView itemView);
|
||||
|
||||
/**
|
||||
* Filter item by child index and item data.
|
||||
*
|
||||
* @param childIndex Indended presentation index of this item
|
||||
* @param item Item to present
|
||||
* @return true if this item should be included in this menu presentation; false otherwise
|
||||
*/
|
||||
public boolean shouldIncludeItem(int childIndex, MenuItemImpl item) {
|
||||
return true;
|
||||
}
|
||||
|
||||
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
|
||||
if (mCallback != null) {
|
||||
mCallback.onCloseMenu(menu, allMenusAreClosing);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onSubMenuSelected(SubMenuBuilder menu) {
|
||||
if (mCallback != null) {
|
||||
return mCallback.onOpenSubMenu(menu);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean flagActionItems() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public int getId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
public void setId(int id) {
|
||||
mId = id;
|
||||
}
|
||||
}
|
|
@ -1,278 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import com.actionbarsherlock.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.CheckBox;
|
||||
import android.widget.CompoundButton;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RadioButton;
|
||||
import android.widget.TextView;
|
||||
|
||||
/**
|
||||
* The item view for each item in the ListView-based MenuViews.
|
||||
*/
|
||||
public class ListMenuItemView extends LinearLayout implements MenuView.ItemView {
|
||||
private MenuItemImpl mItemData;
|
||||
|
||||
private ImageView mIconView;
|
||||
private RadioButton mRadioButton;
|
||||
private TextView mTitleView;
|
||||
private CheckBox mCheckBox;
|
||||
private TextView mShortcutView;
|
||||
|
||||
private Drawable mBackground;
|
||||
private int mTextAppearance;
|
||||
private Context mTextAppearanceContext;
|
||||
private boolean mPreserveIconSpacing;
|
||||
|
||||
//UNUSED private int mMenuType;
|
||||
|
||||
private LayoutInflater mInflater;
|
||||
|
||||
private boolean mForceShowIcon;
|
||||
|
||||
final Context mContext;
|
||||
|
||||
public ListMenuItemView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs);
|
||||
mContext = context;
|
||||
|
||||
TypedArray a =
|
||||
context.obtainStyledAttributes(
|
||||
attrs, R.styleable.SherlockMenuView, defStyle, 0);
|
||||
|
||||
mBackground = a.getDrawable(R.styleable.SherlockMenuView_itemBackground);
|
||||
mTextAppearance = a.getResourceId(R.styleable.
|
||||
SherlockMenuView_itemTextAppearance, -1);
|
||||
mPreserveIconSpacing = a.getBoolean(
|
||||
R.styleable.SherlockMenuView_preserveIconSpacing, false);
|
||||
mTextAppearanceContext = context;
|
||||
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
public ListMenuItemView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
|
||||
setBackgroundDrawable(mBackground);
|
||||
|
||||
mTitleView = (TextView) findViewById(R.id.abs__title);
|
||||
if (mTextAppearance != -1) {
|
||||
mTitleView.setTextAppearance(mTextAppearanceContext,
|
||||
mTextAppearance);
|
||||
}
|
||||
|
||||
mShortcutView = (TextView) findViewById(R.id.abs__shortcut);
|
||||
}
|
||||
|
||||
public void initialize(MenuItemImpl itemData, int menuType) {
|
||||
mItemData = itemData;
|
||||
//UNUSED mMenuType = menuType;
|
||||
|
||||
setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE);
|
||||
|
||||
setTitle(itemData.getTitleForItemView(this));
|
||||
setCheckable(itemData.isCheckable());
|
||||
setShortcut(itemData.shouldShowShortcut(), itemData.getShortcut());
|
||||
setIcon(itemData.getIcon());
|
||||
setEnabled(itemData.isEnabled());
|
||||
}
|
||||
|
||||
public void setForceShowIcon(boolean forceShow) {
|
||||
mPreserveIconSpacing = mForceShowIcon = forceShow;
|
||||
}
|
||||
|
||||
public void setTitle(CharSequence title) {
|
||||
if (title != null) {
|
||||
mTitleView.setText(title);
|
||||
|
||||
if (mTitleView.getVisibility() != VISIBLE) mTitleView.setVisibility(VISIBLE);
|
||||
} else {
|
||||
if (mTitleView.getVisibility() != GONE) mTitleView.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
public MenuItemImpl getItemData() {
|
||||
return mItemData;
|
||||
}
|
||||
|
||||
public void setCheckable(boolean checkable) {
|
||||
|
||||
if (!checkable && mRadioButton == null && mCheckBox == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mRadioButton == null) {
|
||||
insertRadioButton();
|
||||
}
|
||||
if (mCheckBox == null) {
|
||||
insertCheckBox();
|
||||
}
|
||||
|
||||
// Depending on whether its exclusive check or not, the checkbox or
|
||||
// radio button will be the one in use (and the other will be otherCompoundButton)
|
||||
final CompoundButton compoundButton;
|
||||
final CompoundButton otherCompoundButton;
|
||||
|
||||
if (mItemData.isExclusiveCheckable()) {
|
||||
compoundButton = mRadioButton;
|
||||
otherCompoundButton = mCheckBox;
|
||||
} else {
|
||||
compoundButton = mCheckBox;
|
||||
otherCompoundButton = mRadioButton;
|
||||
}
|
||||
|
||||
if (checkable) {
|
||||
compoundButton.setChecked(mItemData.isChecked());
|
||||
|
||||
final int newVisibility = checkable ? VISIBLE : GONE;
|
||||
if (compoundButton.getVisibility() != newVisibility) {
|
||||
compoundButton.setVisibility(newVisibility);
|
||||
}
|
||||
|
||||
// Make sure the other compound button isn't visible
|
||||
if (otherCompoundButton.getVisibility() != GONE) {
|
||||
otherCompoundButton.setVisibility(GONE);
|
||||
}
|
||||
} else {
|
||||
mCheckBox.setVisibility(GONE);
|
||||
mRadioButton.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
public void setChecked(boolean checked) {
|
||||
CompoundButton compoundButton;
|
||||
|
||||
if (mItemData.isExclusiveCheckable()) {
|
||||
if (mRadioButton == null) {
|
||||
insertRadioButton();
|
||||
}
|
||||
compoundButton = mRadioButton;
|
||||
} else {
|
||||
if (mCheckBox == null) {
|
||||
insertCheckBox();
|
||||
}
|
||||
compoundButton = mCheckBox;
|
||||
}
|
||||
|
||||
compoundButton.setChecked(checked);
|
||||
}
|
||||
|
||||
public void setShortcut(boolean showShortcut, char shortcutKey) {
|
||||
final int newVisibility = (showShortcut && mItemData.shouldShowShortcut())
|
||||
? VISIBLE : GONE;
|
||||
|
||||
if (newVisibility == VISIBLE) {
|
||||
mShortcutView.setText(mItemData.getShortcutLabel());
|
||||
}
|
||||
|
||||
if (mShortcutView.getVisibility() != newVisibility) {
|
||||
mShortcutView.setVisibility(newVisibility);
|
||||
}
|
||||
}
|
||||
|
||||
public void setIcon(Drawable icon) {
|
||||
final boolean showIcon = mItemData.shouldShowIcon() || mForceShowIcon;
|
||||
if (!showIcon && !mPreserveIconSpacing) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIconView == null && icon == null && !mPreserveIconSpacing) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIconView == null) {
|
||||
insertIconView();
|
||||
}
|
||||
|
||||
if (icon != null || mPreserveIconSpacing) {
|
||||
mIconView.setImageDrawable(showIcon ? icon : null);
|
||||
|
||||
if (mIconView.getVisibility() != VISIBLE) {
|
||||
mIconView.setVisibility(VISIBLE);
|
||||
}
|
||||
} else {
|
||||
mIconView.setVisibility(GONE);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
if (mIconView != null && mPreserveIconSpacing) {
|
||||
// Enforce minimum icon spacing
|
||||
ViewGroup.LayoutParams lp = getLayoutParams();
|
||||
LayoutParams iconLp = (LayoutParams) mIconView.getLayoutParams();
|
||||
if (lp.height > 0 && iconLp.width <= 0) {
|
||||
iconLp.width = lp.height;
|
||||
}
|
||||
}
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
}
|
||||
|
||||
private void insertIconView() {
|
||||
LayoutInflater inflater = getInflater();
|
||||
mIconView = (ImageView) inflater.inflate(R.layout.abs__list_menu_item_icon,
|
||||
this, false);
|
||||
addView(mIconView, 0);
|
||||
}
|
||||
|
||||
private void insertRadioButton() {
|
||||
LayoutInflater inflater = getInflater();
|
||||
mRadioButton =
|
||||
(RadioButton) inflater.inflate(R.layout.abs__list_menu_item_radio,
|
||||
this, false);
|
||||
addView(mRadioButton);
|
||||
}
|
||||
|
||||
private void insertCheckBox() {
|
||||
LayoutInflater inflater = getInflater();
|
||||
mCheckBox =
|
||||
(CheckBox) inflater.inflate(R.layout.abs__list_menu_item_checkbox,
|
||||
this, false);
|
||||
addView(mCheckBox);
|
||||
}
|
||||
|
||||
public boolean prefersCondensedTitle() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean showsIcon() {
|
||||
return mForceShowIcon;
|
||||
}
|
||||
|
||||
private LayoutInflater getInflater() {
|
||||
if (mInflater == null) {
|
||||
mInflater = LayoutInflater.from(mContext);
|
||||
}
|
||||
return mInflater;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,647 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.Log;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewDebug;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.actionbarsherlock.view.ActionProvider;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import com.actionbarsherlock.view.SubMenu;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public final class MenuItemImpl implements MenuItem {
|
||||
private static final String TAG = "MenuItemImpl";
|
||||
|
||||
private static final int SHOW_AS_ACTION_MASK = SHOW_AS_ACTION_NEVER |
|
||||
SHOW_AS_ACTION_IF_ROOM |
|
||||
SHOW_AS_ACTION_ALWAYS;
|
||||
|
||||
private final int mId;
|
||||
private final int mGroup;
|
||||
private final int mCategoryOrder;
|
||||
private final int mOrdering;
|
||||
private CharSequence mTitle;
|
||||
private CharSequence mTitleCondensed;
|
||||
private Intent mIntent;
|
||||
private char mShortcutNumericChar;
|
||||
private char mShortcutAlphabeticChar;
|
||||
|
||||
/** The icon's drawable which is only created as needed */
|
||||
private Drawable mIconDrawable;
|
||||
/**
|
||||
* The icon's resource ID which is used to get the Drawable when it is
|
||||
* needed (if the Drawable isn't already obtained--only one of the two is
|
||||
* needed).
|
||||
*/
|
||||
private int mIconResId = NO_ICON;
|
||||
|
||||
/** The menu to which this item belongs */
|
||||
private MenuBuilder mMenu;
|
||||
/** If this item should launch a sub menu, this is the sub menu to launch */
|
||||
private SubMenuBuilder mSubMenu;
|
||||
|
||||
private Runnable mItemCallback;
|
||||
private MenuItem.OnMenuItemClickListener mClickListener;
|
||||
|
||||
private int mFlags = ENABLED;
|
||||
private static final int CHECKABLE = 0x00000001;
|
||||
private static final int CHECKED = 0x00000002;
|
||||
private static final int EXCLUSIVE = 0x00000004;
|
||||
private static final int HIDDEN = 0x00000008;
|
||||
private static final int ENABLED = 0x00000010;
|
||||
private static final int IS_ACTION = 0x00000020;
|
||||
|
||||
private int mShowAsAction = SHOW_AS_ACTION_NEVER;
|
||||
|
||||
private View mActionView;
|
||||
private ActionProvider mActionProvider;
|
||||
private OnActionExpandListener mOnActionExpandListener;
|
||||
private boolean mIsActionViewExpanded = false;
|
||||
|
||||
/** Used for the icon resource ID if this item does not have an icon */
|
||||
static final int NO_ICON = 0;
|
||||
|
||||
/**
|
||||
* Current use case is for context menu: Extra information linked to the
|
||||
* View that added this item to the context menu.
|
||||
*/
|
||||
private ContextMenuInfo mMenuInfo;
|
||||
|
||||
private static String sPrependShortcutLabel;
|
||||
private static String sEnterShortcutLabel;
|
||||
private static String sDeleteShortcutLabel;
|
||||
private static String sSpaceShortcutLabel;
|
||||
|
||||
|
||||
/**
|
||||
* Instantiates this menu item.
|
||||
*
|
||||
* @param menu
|
||||
* @param group Item ordering grouping control. The item will be added after
|
||||
* all other items whose order is <= this number, and before any
|
||||
* that are larger than it. This can also be used to define
|
||||
* groups of items for batch state changes. Normally use 0.
|
||||
* @param id Unique item ID. Use 0 if you do not need a unique ID.
|
||||
* @param categoryOrder The ordering for this item.
|
||||
* @param title The text to display for the item.
|
||||
*/
|
||||
MenuItemImpl(MenuBuilder menu, int group, int id, int categoryOrder, int ordering,
|
||||
CharSequence title, int showAsAction) {
|
||||
|
||||
/* TODO if (sPrependShortcutLabel == null) {
|
||||
// This is instantiated from the UI thread, so no chance of sync issues
|
||||
sPrependShortcutLabel = menu.getContext().getResources().getString(
|
||||
com.android.internal.R.string.prepend_shortcut_label);
|
||||
sEnterShortcutLabel = menu.getContext().getResources().getString(
|
||||
com.android.internal.R.string.menu_enter_shortcut_label);
|
||||
sDeleteShortcutLabel = menu.getContext().getResources().getString(
|
||||
com.android.internal.R.string.menu_delete_shortcut_label);
|
||||
sSpaceShortcutLabel = menu.getContext().getResources().getString(
|
||||
com.android.internal.R.string.menu_space_shortcut_label);
|
||||
}*/
|
||||
|
||||
mMenu = menu;
|
||||
mId = id;
|
||||
mGroup = group;
|
||||
mCategoryOrder = categoryOrder;
|
||||
mOrdering = ordering;
|
||||
mTitle = title;
|
||||
mShowAsAction = showAsAction;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the item by calling various listeners or callbacks.
|
||||
*
|
||||
* @return true if the invocation was handled, false otherwise
|
||||
*/
|
||||
public boolean invoke() {
|
||||
if (mClickListener != null &&
|
||||
mClickListener.onMenuItemClick(this)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mMenu.dispatchMenuItemSelected(mMenu.getRootMenu(), this)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mItemCallback != null) {
|
||||
mItemCallback.run();
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mIntent != null) {
|
||||
try {
|
||||
mMenu.getContext().startActivity(mIntent);
|
||||
return true;
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Log.e(TAG, "Can't find activity to handle intent; ignoring", e);
|
||||
}
|
||||
}
|
||||
|
||||
if (mActionProvider != null && mActionProvider.onPerformDefaultAction()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isEnabled() {
|
||||
return (mFlags & ENABLED) != 0;
|
||||
}
|
||||
|
||||
public MenuItem setEnabled(boolean enabled) {
|
||||
if (enabled) {
|
||||
mFlags |= ENABLED;
|
||||
} else {
|
||||
mFlags &= ~ENABLED;
|
||||
}
|
||||
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public int getGroupId() {
|
||||
return mGroup;
|
||||
}
|
||||
|
||||
@ViewDebug.CapturedViewProperty
|
||||
public int getItemId() {
|
||||
return mId;
|
||||
}
|
||||
|
||||
public int getOrder() {
|
||||
return mCategoryOrder;
|
||||
}
|
||||
|
||||
public int getOrdering() {
|
||||
return mOrdering;
|
||||
}
|
||||
|
||||
public Intent getIntent() {
|
||||
return mIntent;
|
||||
}
|
||||
|
||||
public MenuItem setIntent(Intent intent) {
|
||||
mIntent = intent;
|
||||
return this;
|
||||
}
|
||||
|
||||
Runnable getCallback() {
|
||||
return mItemCallback;
|
||||
}
|
||||
|
||||
public MenuItem setCallback(Runnable callback) {
|
||||
mItemCallback = callback;
|
||||
return this;
|
||||
}
|
||||
|
||||
public char getAlphabeticShortcut() {
|
||||
return mShortcutAlphabeticChar;
|
||||
}
|
||||
|
||||
public MenuItem setAlphabeticShortcut(char alphaChar) {
|
||||
if (mShortcutAlphabeticChar == alphaChar) return this;
|
||||
|
||||
mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
|
||||
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public char getNumericShortcut() {
|
||||
return mShortcutNumericChar;
|
||||
}
|
||||
|
||||
public MenuItem setNumericShortcut(char numericChar) {
|
||||
if (mShortcutNumericChar == numericChar) return this;
|
||||
|
||||
mShortcutNumericChar = numericChar;
|
||||
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setShortcut(char numericChar, char alphaChar) {
|
||||
mShortcutNumericChar = numericChar;
|
||||
mShortcutAlphabeticChar = Character.toLowerCase(alphaChar);
|
||||
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The active shortcut (based on QWERTY-mode of the menu).
|
||||
*/
|
||||
char getShortcut() {
|
||||
return (mMenu.isQwertyMode() ? mShortcutAlphabeticChar : mShortcutNumericChar);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The label to show for the shortcut. This includes the chording
|
||||
* key (for example 'Menu+a'). Also, any non-human readable
|
||||
* characters should be human readable (for example 'Menu+enter').
|
||||
*/
|
||||
String getShortcutLabel() {
|
||||
|
||||
char shortcut = getShortcut();
|
||||
if (shortcut == 0) {
|
||||
return "";
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder(sPrependShortcutLabel);
|
||||
switch (shortcut) {
|
||||
|
||||
case '\n':
|
||||
sb.append(sEnterShortcutLabel);
|
||||
break;
|
||||
|
||||
case '\b':
|
||||
sb.append(sDeleteShortcutLabel);
|
||||
break;
|
||||
|
||||
case ' ':
|
||||
sb.append(sSpaceShortcutLabel);
|
||||
break;
|
||||
|
||||
default:
|
||||
sb.append(shortcut);
|
||||
break;
|
||||
}
|
||||
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether this menu item should be showing shortcuts (depends on
|
||||
* whether the menu should show shortcuts and whether this item has
|
||||
* a shortcut defined)
|
||||
*/
|
||||
boolean shouldShowShortcut() {
|
||||
// Show shortcuts if the menu is supposed to show shortcuts AND this item has a shortcut
|
||||
return mMenu.isShortcutsVisible() && (getShortcut() != 0);
|
||||
}
|
||||
|
||||
public SubMenu getSubMenu() {
|
||||
return mSubMenu;
|
||||
}
|
||||
|
||||
public boolean hasSubMenu() {
|
||||
return mSubMenu != null;
|
||||
}
|
||||
|
||||
void setSubMenu(SubMenuBuilder subMenu) {
|
||||
mSubMenu = subMenu;
|
||||
|
||||
subMenu.setHeaderTitle(getTitle());
|
||||
}
|
||||
|
||||
@ViewDebug.CapturedViewProperty
|
||||
public CharSequence getTitle() {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the title for a particular {@link ItemView}
|
||||
*
|
||||
* @param itemView The ItemView that is receiving the title
|
||||
* @return Either the title or condensed title based on what the ItemView
|
||||
* prefers
|
||||
*/
|
||||
CharSequence getTitleForItemView(MenuView.ItemView itemView) {
|
||||
return ((itemView != null) && itemView.prefersCondensedTitle())
|
||||
? getTitleCondensed()
|
||||
: getTitle();
|
||||
}
|
||||
|
||||
public MenuItem setTitle(CharSequence title) {
|
||||
mTitle = title;
|
||||
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
if (mSubMenu != null) {
|
||||
mSubMenu.setHeaderTitle(title);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setTitle(int title) {
|
||||
return setTitle(mMenu.getContext().getString(title));
|
||||
}
|
||||
|
||||
public CharSequence getTitleCondensed() {
|
||||
return mTitleCondensed != null ? mTitleCondensed : mTitle;
|
||||
}
|
||||
|
||||
public MenuItem setTitleCondensed(CharSequence title) {
|
||||
mTitleCondensed = title;
|
||||
|
||||
// Could use getTitle() in the loop below, but just cache what it would do here
|
||||
if (title == null) {
|
||||
title = mTitle;
|
||||
}
|
||||
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public Drawable getIcon() {
|
||||
if (mIconDrawable != null) {
|
||||
return mIconDrawable;
|
||||
}
|
||||
|
||||
if (mIconResId != NO_ICON) {
|
||||
return mMenu.getResources().getDrawable(mIconResId);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public MenuItem setIcon(Drawable icon) {
|
||||
mIconResId = NO_ICON;
|
||||
mIconDrawable = icon;
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setIcon(int iconResId) {
|
||||
mIconDrawable = null;
|
||||
mIconResId = iconResId;
|
||||
|
||||
// If we have a view, we need to push the Drawable to them
|
||||
mMenu.onItemsChanged(false);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean isCheckable() {
|
||||
return (mFlags & CHECKABLE) == CHECKABLE;
|
||||
}
|
||||
|
||||
public MenuItem setCheckable(boolean checkable) {
|
||||
final int oldFlags = mFlags;
|
||||
mFlags = (mFlags & ~CHECKABLE) | (checkable ? CHECKABLE : 0);
|
||||
if (oldFlags != mFlags) {
|
||||
mMenu.onItemsChanged(false);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setExclusiveCheckable(boolean exclusive) {
|
||||
mFlags = (mFlags & ~EXCLUSIVE) | (exclusive ? EXCLUSIVE : 0);
|
||||
}
|
||||
|
||||
public boolean isExclusiveCheckable() {
|
||||
return (mFlags & EXCLUSIVE) != 0;
|
||||
}
|
||||
|
||||
public boolean isChecked() {
|
||||
return (mFlags & CHECKED) == CHECKED;
|
||||
}
|
||||
|
||||
public MenuItem setChecked(boolean checked) {
|
||||
if ((mFlags & EXCLUSIVE) != 0) {
|
||||
// Call the method on the Menu since it knows about the others in this
|
||||
// exclusive checkable group
|
||||
mMenu.setExclusiveItemChecked(this);
|
||||
} else {
|
||||
setCheckedInt(checked);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
void setCheckedInt(boolean checked) {
|
||||
final int oldFlags = mFlags;
|
||||
mFlags = (mFlags & ~CHECKED) | (checked ? CHECKED : 0);
|
||||
if (oldFlags != mFlags) {
|
||||
mMenu.onItemsChanged(false);
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isVisible() {
|
||||
return (mFlags & HIDDEN) == 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Changes the visibility of the item. This method DOES NOT notify the
|
||||
* parent menu of a change in this item, so this should only be called from
|
||||
* methods that will eventually trigger this change. If unsure, use {@link #setVisible(boolean)}
|
||||
* instead.
|
||||
*
|
||||
* @param shown Whether to show (true) or hide (false).
|
||||
* @return Whether the item's shown state was changed
|
||||
*/
|
||||
boolean setVisibleInt(boolean shown) {
|
||||
final int oldFlags = mFlags;
|
||||
mFlags = (mFlags & ~HIDDEN) | (shown ? 0 : HIDDEN);
|
||||
return oldFlags != mFlags;
|
||||
}
|
||||
|
||||
public MenuItem setVisible(boolean shown) {
|
||||
// Try to set the shown state to the given state. If the shown state was changed
|
||||
// (i.e. the previous state isn't the same as given state), notify the parent menu that
|
||||
// the shown state has changed for this item
|
||||
if (setVisibleInt(shown)) mMenu.onItemVisibleChanged(this);
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener clickListener) {
|
||||
mClickListener = clickListener;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return mTitle.toString();
|
||||
}
|
||||
|
||||
void setMenuInfo(ContextMenuInfo menuInfo) {
|
||||
mMenuInfo = menuInfo;
|
||||
}
|
||||
|
||||
public ContextMenuInfo getMenuInfo() {
|
||||
return mMenuInfo;
|
||||
}
|
||||
|
||||
public void actionFormatChanged() {
|
||||
mMenu.onItemActionRequestChanged(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Whether the menu should show icons for menu items.
|
||||
*/
|
||||
public boolean shouldShowIcon() {
|
||||
return mMenu.getOptionalIconsVisible();
|
||||
}
|
||||
|
||||
public boolean isActionButton() {
|
||||
return (mFlags & IS_ACTION) == IS_ACTION;
|
||||
}
|
||||
|
||||
public boolean requestsActionButton() {
|
||||
return (mShowAsAction & SHOW_AS_ACTION_IF_ROOM) == SHOW_AS_ACTION_IF_ROOM;
|
||||
}
|
||||
|
||||
public boolean requiresActionButton() {
|
||||
return (mShowAsAction & SHOW_AS_ACTION_ALWAYS) == SHOW_AS_ACTION_ALWAYS;
|
||||
}
|
||||
|
||||
public void setIsActionButton(boolean isActionButton) {
|
||||
if (isActionButton) {
|
||||
mFlags |= IS_ACTION;
|
||||
} else {
|
||||
mFlags &= ~IS_ACTION;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean showsTextAsAction() {
|
||||
return (mShowAsAction & SHOW_AS_ACTION_WITH_TEXT) == SHOW_AS_ACTION_WITH_TEXT;
|
||||
}
|
||||
|
||||
public void setShowAsAction(int actionEnum) {
|
||||
switch (actionEnum & SHOW_AS_ACTION_MASK) {
|
||||
case SHOW_AS_ACTION_ALWAYS:
|
||||
case SHOW_AS_ACTION_IF_ROOM:
|
||||
case SHOW_AS_ACTION_NEVER:
|
||||
// Looks good!
|
||||
break;
|
||||
|
||||
default:
|
||||
// Mutually exclusive options selected!
|
||||
throw new IllegalArgumentException("SHOW_AS_ACTION_ALWAYS, SHOW_AS_ACTION_IF_ROOM,"
|
||||
+ " and SHOW_AS_ACTION_NEVER are mutually exclusive.");
|
||||
}
|
||||
mShowAsAction = actionEnum;
|
||||
mMenu.onItemActionRequestChanged(this);
|
||||
}
|
||||
|
||||
public MenuItem setActionView(View view) {
|
||||
mActionView = view;
|
||||
mActionProvider = null;
|
||||
if (view != null && view.getId() == View.NO_ID && mId > 0) {
|
||||
view.setId(mId);
|
||||
}
|
||||
mMenu.onItemActionRequestChanged(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MenuItem setActionView(int resId) {
|
||||
final Context context = mMenu.getContext();
|
||||
final LayoutInflater inflater = LayoutInflater.from(context);
|
||||
setActionView(inflater.inflate(resId, new LinearLayout(context), false));
|
||||
return this;
|
||||
}
|
||||
|
||||
public View getActionView() {
|
||||
if (mActionView != null) {
|
||||
return mActionView;
|
||||
} else if (mActionProvider != null) {
|
||||
mActionView = mActionProvider.onCreateActionView();
|
||||
return mActionView;
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public ActionProvider getActionProvider() {
|
||||
return mActionProvider;
|
||||
}
|
||||
|
||||
public MenuItem setActionProvider(ActionProvider actionProvider) {
|
||||
mActionView = null;
|
||||
mActionProvider = actionProvider;
|
||||
mMenu.onItemsChanged(true); // Measurement can be changed
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setShowAsActionFlags(int actionEnum) {
|
||||
setShowAsAction(actionEnum);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean expandActionView() {
|
||||
if ((mShowAsAction & SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW) == 0 || mActionView == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (mOnActionExpandListener == null ||
|
||||
mOnActionExpandListener.onMenuItemActionExpand(this)) {
|
||||
return mMenu.expandItemActionView(this);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collapseActionView() {
|
||||
if ((mShowAsAction & SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW) == 0) {
|
||||
return false;
|
||||
}
|
||||
if (mActionView == null) {
|
||||
// We're already collapsed if we have no action view.
|
||||
return true;
|
||||
}
|
||||
|
||||
if (mOnActionExpandListener == null ||
|
||||
mOnActionExpandListener.onMenuItemActionCollapse(this)) {
|
||||
return mMenu.collapseItemActionView(this);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setOnActionExpandListener(OnActionExpandListener listener) {
|
||||
mOnActionExpandListener = listener;
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean hasCollapsibleActionView() {
|
||||
return (mShowAsAction & SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW) != 0 && mActionView != null;
|
||||
}
|
||||
|
||||
public void setActionViewExpanded(boolean isExpanded) {
|
||||
mIsActionViewExpanded = isExpanded;
|
||||
mMenu.onItemsChanged(false);
|
||||
}
|
||||
|
||||
public boolean isActionViewExpanded() {
|
||||
return mIsActionViewExpanded;
|
||||
}
|
||||
}
|
|
@ -1,310 +0,0 @@
|
|||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.View;
|
||||
import com.actionbarsherlock.internal.view.ActionProviderWrapper;
|
||||
import com.actionbarsherlock.internal.widget.CollapsibleActionViewWrapper;
|
||||
import com.actionbarsherlock.view.ActionProvider;
|
||||
import com.actionbarsherlock.view.CollapsibleActionView;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import com.actionbarsherlock.view.SubMenu;
|
||||
|
||||
public class MenuItemWrapper implements MenuItem, android.view.MenuItem.OnMenuItemClickListener {
|
||||
private final android.view.MenuItem mNativeItem;
|
||||
private SubMenu mSubMenu = null;
|
||||
private OnMenuItemClickListener mMenuItemClickListener = null;
|
||||
private OnActionExpandListener mActionExpandListener = null;
|
||||
private android.view.MenuItem.OnActionExpandListener mNativeActionExpandListener = null;
|
||||
|
||||
|
||||
public MenuItemWrapper(android.view.MenuItem nativeItem) {
|
||||
if (nativeItem == null) {
|
||||
throw new IllegalStateException("Wrapped menu item cannot be null.");
|
||||
}
|
||||
mNativeItem = nativeItem;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getItemId() {
|
||||
return mNativeItem.getItemId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getGroupId() {
|
||||
return mNativeItem.getGroupId();
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getOrder() {
|
||||
return mNativeItem.getOrder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setTitle(CharSequence title) {
|
||||
mNativeItem.setTitle(title);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setTitle(int title) {
|
||||
mNativeItem.setTitle(title);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTitle() {
|
||||
return mNativeItem.getTitle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setTitleCondensed(CharSequence title) {
|
||||
mNativeItem.setTitleCondensed(title);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getTitleCondensed() {
|
||||
return mNativeItem.getTitleCondensed();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setIcon(Drawable icon) {
|
||||
mNativeItem.setIcon(icon);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setIcon(int iconRes) {
|
||||
mNativeItem.setIcon(iconRes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Drawable getIcon() {
|
||||
return mNativeItem.getIcon();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setIntent(Intent intent) {
|
||||
mNativeItem.setIntent(intent);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Intent getIntent() {
|
||||
return mNativeItem.getIntent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setShortcut(char numericChar, char alphaChar) {
|
||||
mNativeItem.setShortcut(numericChar, alphaChar);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setNumericShortcut(char numericChar) {
|
||||
mNativeItem.setNumericShortcut(numericChar);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getNumericShortcut() {
|
||||
return mNativeItem.getNumericShortcut();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setAlphabeticShortcut(char alphaChar) {
|
||||
mNativeItem.setAlphabeticShortcut(alphaChar);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public char getAlphabeticShortcut() {
|
||||
return mNativeItem.getAlphabeticShortcut();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setCheckable(boolean checkable) {
|
||||
mNativeItem.setCheckable(checkable);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCheckable() {
|
||||
return mNativeItem.isCheckable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setChecked(boolean checked) {
|
||||
mNativeItem.setChecked(checked);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isChecked() {
|
||||
return mNativeItem.isChecked();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setVisible(boolean visible) {
|
||||
mNativeItem.setVisible(visible);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isVisible() {
|
||||
return mNativeItem.isVisible();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setEnabled(boolean enabled) {
|
||||
mNativeItem.setEnabled(enabled);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isEnabled() {
|
||||
return mNativeItem.isEnabled();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasSubMenu() {
|
||||
return mNativeItem.hasSubMenu();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu getSubMenu() {
|
||||
if (hasSubMenu() && (mSubMenu == null)) {
|
||||
mSubMenu = new SubMenuWrapper(mNativeItem.getSubMenu());
|
||||
}
|
||||
return mSubMenu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) {
|
||||
mMenuItemClickListener = menuItemClickListener;
|
||||
//Register ourselves as the listener to proxy
|
||||
mNativeItem.setOnMenuItemClickListener(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemClick(android.view.MenuItem item) {
|
||||
if (mMenuItemClickListener != null) {
|
||||
return mMenuItemClickListener.onMenuItemClick(this);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ContextMenuInfo getMenuInfo() {
|
||||
return mNativeItem.getMenuInfo();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShowAsAction(int actionEnum) {
|
||||
mNativeItem.setShowAsAction(actionEnum);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setShowAsActionFlags(int actionEnum) {
|
||||
mNativeItem.setShowAsActionFlags(actionEnum);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setActionView(View view) {
|
||||
if (view != null && view instanceof CollapsibleActionView) {
|
||||
view = new CollapsibleActionViewWrapper(view);
|
||||
}
|
||||
mNativeItem.setActionView(view);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setActionView(int resId) {
|
||||
//Allow the native menu to inflate the resource
|
||||
mNativeItem.setActionView(resId);
|
||||
if (resId != 0) {
|
||||
//Get newly created view
|
||||
View view = mNativeItem.getActionView();
|
||||
if (view instanceof CollapsibleActionView) {
|
||||
//Wrap it and re-set it
|
||||
mNativeItem.setActionView(new CollapsibleActionViewWrapper(view));
|
||||
}
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getActionView() {
|
||||
View actionView = mNativeItem.getActionView();
|
||||
if (actionView instanceof CollapsibleActionViewWrapper) {
|
||||
return ((CollapsibleActionViewWrapper)actionView).unwrap();
|
||||
}
|
||||
return actionView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setActionProvider(ActionProvider actionProvider) {
|
||||
mNativeItem.setActionProvider(new ActionProviderWrapper(actionProvider));
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ActionProvider getActionProvider() {
|
||||
android.view.ActionProvider nativeProvider = mNativeItem.getActionProvider();
|
||||
if (nativeProvider != null && nativeProvider instanceof ActionProviderWrapper) {
|
||||
return ((ActionProviderWrapper)nativeProvider).unwrap();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean expandActionView() {
|
||||
return mNativeItem.expandActionView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collapseActionView() {
|
||||
return mNativeItem.collapseActionView();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isActionViewExpanded() {
|
||||
return mNativeItem.isActionViewExpanded();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem setOnActionExpandListener(OnActionExpandListener listener) {
|
||||
mActionExpandListener = listener;
|
||||
|
||||
if (mNativeActionExpandListener == null) {
|
||||
mNativeActionExpandListener = new android.view.MenuItem.OnActionExpandListener() {
|
||||
@Override
|
||||
public boolean onMenuItemActionExpand(android.view.MenuItem menuItem) {
|
||||
if (mActionExpandListener != null) {
|
||||
return mActionExpandListener.onMenuItemActionExpand(MenuItemWrapper.this);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onMenuItemActionCollapse(android.view.MenuItem menuItem) {
|
||||
if (mActionExpandListener != null) {
|
||||
return mActionExpandListener.onMenuItemActionCollapse(MenuItemWrapper.this);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
//Register our inner-class as the listener to proxy method calls
|
||||
mNativeItem.setOnActionExpandListener(mNativeActionExpandListener);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -1,376 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.database.DataSetObserver;
|
||||
import android.os.Parcelable;
|
||||
import android.view.KeyEvent;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.View.MeasureSpec;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewTreeObserver;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.FrameLayout;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.PopupWindow;
|
||||
import com.actionbarsherlock.R;
|
||||
import com.actionbarsherlock.internal.view.View_HasStateListenerSupport;
|
||||
import com.actionbarsherlock.internal.view.View_OnAttachStateChangeListener;
|
||||
import com.actionbarsherlock.internal.widget.IcsListPopupWindow;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
|
||||
/**
|
||||
* Presents a menu as a small, simple popup anchored to another view.
|
||||
* @hide
|
||||
*/
|
||||
public class MenuPopupHelper implements AdapterView.OnItemClickListener, View.OnKeyListener,
|
||||
ViewTreeObserver.OnGlobalLayoutListener, PopupWindow.OnDismissListener,
|
||||
View_OnAttachStateChangeListener, MenuPresenter {
|
||||
//UNUSED private static final String TAG = "MenuPopupHelper";
|
||||
|
||||
static final int ITEM_LAYOUT = R.layout.abs__popup_menu_item_layout;
|
||||
|
||||
private Context mContext;
|
||||
private LayoutInflater mInflater;
|
||||
private IcsListPopupWindow mPopup;
|
||||
private MenuBuilder mMenu;
|
||||
private int mPopupMaxWidth;
|
||||
private View mAnchorView;
|
||||
private boolean mOverflowOnly;
|
||||
private ViewTreeObserver mTreeObserver;
|
||||
|
||||
private MenuAdapter mAdapter;
|
||||
|
||||
private Callback mPresenterCallback;
|
||||
|
||||
boolean mForceShowIcon;
|
||||
|
||||
private ViewGroup mMeasureParent;
|
||||
|
||||
public MenuPopupHelper(Context context, MenuBuilder menu) {
|
||||
this(context, menu, null, false);
|
||||
}
|
||||
|
||||
public MenuPopupHelper(Context context, MenuBuilder menu, View anchorView) {
|
||||
this(context, menu, anchorView, false);
|
||||
}
|
||||
|
||||
public MenuPopupHelper(Context context, MenuBuilder menu,
|
||||
View anchorView, boolean overflowOnly) {
|
||||
mContext = context;
|
||||
mInflater = LayoutInflater.from(context);
|
||||
mMenu = menu;
|
||||
mOverflowOnly = overflowOnly;
|
||||
|
||||
final Resources res = context.getResources();
|
||||
mPopupMaxWidth = Math.max(res.getDisplayMetrics().widthPixels / 2,
|
||||
res.getDimensionPixelSize(R.dimen.abs__config_prefDialogWidth));
|
||||
|
||||
mAnchorView = anchorView;
|
||||
|
||||
menu.addMenuPresenter(this);
|
||||
}
|
||||
|
||||
public void setAnchorView(View anchor) {
|
||||
mAnchorView = anchor;
|
||||
}
|
||||
|
||||
public void setForceShowIcon(boolean forceShow) {
|
||||
mForceShowIcon = forceShow;
|
||||
}
|
||||
|
||||
public void show() {
|
||||
if (!tryShow()) {
|
||||
throw new IllegalStateException("MenuPopupHelper cannot be used without an anchor");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean tryShow() {
|
||||
mPopup = new IcsListPopupWindow(mContext, null, R.attr.popupMenuStyle);
|
||||
mPopup.setOnDismissListener(this);
|
||||
mPopup.setOnItemClickListener(this);
|
||||
|
||||
mAdapter = new MenuAdapter(mMenu);
|
||||
mPopup.setAdapter(mAdapter);
|
||||
mPopup.setModal(true);
|
||||
|
||||
View anchor = mAnchorView;
|
||||
if (anchor != null) {
|
||||
final boolean addGlobalListener = mTreeObserver == null;
|
||||
mTreeObserver = anchor.getViewTreeObserver(); // Refresh to latest
|
||||
if (addGlobalListener) mTreeObserver.addOnGlobalLayoutListener(this);
|
||||
((View_HasStateListenerSupport)anchor).addOnAttachStateChangeListener(this);
|
||||
mPopup.setAnchorView(anchor);
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
mPopup.setContentWidth(Math.min(measureContentWidth(mAdapter), mPopupMaxWidth));
|
||||
mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
|
||||
mPopup.show();
|
||||
mPopup.getListView().setOnKeyListener(this);
|
||||
return true;
|
||||
}
|
||||
|
||||
public void dismiss() {
|
||||
if (isShowing()) {
|
||||
mPopup.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
public void onDismiss() {
|
||||
mPopup = null;
|
||||
mMenu.close();
|
||||
if (mTreeObserver != null) {
|
||||
if (!mTreeObserver.isAlive()) mTreeObserver = mAnchorView.getViewTreeObserver();
|
||||
mTreeObserver.removeGlobalOnLayoutListener(this);
|
||||
mTreeObserver = null;
|
||||
}
|
||||
((View_HasStateListenerSupport)mAnchorView).removeOnAttachStateChangeListener(this);
|
||||
}
|
||||
|
||||
public boolean isShowing() {
|
||||
return mPopup != null && mPopup.isShowing();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
MenuAdapter adapter = mAdapter;
|
||||
adapter.mAdapterMenu.performItemAction(adapter.getItem(position), 0);
|
||||
}
|
||||
|
||||
public boolean onKey(View v, int keyCode, KeyEvent event) {
|
||||
if (event.getAction() == KeyEvent.ACTION_UP && keyCode == KeyEvent.KEYCODE_MENU) {
|
||||
dismiss();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private int measureContentWidth(ListAdapter adapter) {
|
||||
// Menus don't tend to be long, so this is more sane than it looks.
|
||||
int width = 0;
|
||||
View itemView = null;
|
||||
int itemType = 0;
|
||||
final int widthMeasureSpec =
|
||||
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
final int heightMeasureSpec =
|
||||
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
final int count = adapter.getCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final int positionType = adapter.getItemViewType(i);
|
||||
if (positionType != itemType) {
|
||||
itemType = positionType;
|
||||
itemView = null;
|
||||
}
|
||||
if (mMeasureParent == null) {
|
||||
mMeasureParent = new FrameLayout(mContext);
|
||||
}
|
||||
itemView = adapter.getView(i, itemView, mMeasureParent);
|
||||
itemView.measure(widthMeasureSpec, heightMeasureSpec);
|
||||
width = Math.max(width, itemView.getMeasuredWidth());
|
||||
}
|
||||
return width;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onGlobalLayout() {
|
||||
if (isShowing()) {
|
||||
final View anchor = mAnchorView;
|
||||
if (anchor == null || !anchor.isShown()) {
|
||||
dismiss();
|
||||
} else if (isShowing()) {
|
||||
// Recompute window size and position
|
||||
mPopup.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewAttachedToWindow(View v) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View v) {
|
||||
if (mTreeObserver != null) {
|
||||
if (!mTreeObserver.isAlive()) mTreeObserver = v.getViewTreeObserver();
|
||||
mTreeObserver.removeGlobalOnLayoutListener(this);
|
||||
}
|
||||
((View_HasStateListenerSupport)v).removeOnAttachStateChangeListener(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initForMenu(Context context, MenuBuilder menu) {
|
||||
// Don't need to do anything; we added as a presenter in the constructor.
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuView getMenuView(ViewGroup root) {
|
||||
throw new UnsupportedOperationException("MenuPopupHelpers manage their own views");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateMenuView(boolean cleared) {
|
||||
if (mAdapter != null) mAdapter.notifyDataSetChanged();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCallback(Callback cb) {
|
||||
mPresenterCallback = cb;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
|
||||
if (subMenu.hasVisibleItems()) {
|
||||
MenuPopupHelper subPopup = new MenuPopupHelper(mContext, subMenu, mAnchorView, false);
|
||||
subPopup.setCallback(mPresenterCallback);
|
||||
|
||||
boolean preserveIconSpacing = false;
|
||||
final int count = subMenu.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
MenuItem childItem = subMenu.getItem(i);
|
||||
if (childItem.isVisible() && childItem.getIcon() != null) {
|
||||
preserveIconSpacing = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
subPopup.setForceShowIcon(preserveIconSpacing);
|
||||
|
||||
if (subPopup.tryShow()) {
|
||||
if (mPresenterCallback != null) {
|
||||
mPresenterCallback.onOpenSubMenu(subMenu);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
|
||||
// Only care about the (sub)menu we're presenting.
|
||||
if (menu != mMenu) return;
|
||||
|
||||
dismiss();
|
||||
if (mPresenterCallback != null) {
|
||||
mPresenterCallback.onCloseMenu(menu, allMenusAreClosing);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean flagActionItems() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getId() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parcelable onSaveInstanceState() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreInstanceState(Parcelable state) {
|
||||
}
|
||||
|
||||
private class MenuAdapter extends BaseAdapter {
|
||||
private MenuBuilder mAdapterMenu;
|
||||
private int mExpandedIndex = -1;
|
||||
|
||||
public MenuAdapter(MenuBuilder menu) {
|
||||
mAdapterMenu = menu;
|
||||
registerDataSetObserver(new ExpandedIndexObserver());
|
||||
findExpandedIndex();
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
ArrayList<MenuItemImpl> items = mOverflowOnly ?
|
||||
mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems();
|
||||
if (mExpandedIndex < 0) {
|
||||
return items.size();
|
||||
}
|
||||
return items.size() - 1;
|
||||
}
|
||||
|
||||
public MenuItemImpl getItem(int position) {
|
||||
ArrayList<MenuItemImpl> items = mOverflowOnly ?
|
||||
mAdapterMenu.getNonActionItems() : mAdapterMenu.getVisibleItems();
|
||||
if (mExpandedIndex >= 0 && position >= mExpandedIndex) {
|
||||
position++;
|
||||
}
|
||||
return items.get(position);
|
||||
}
|
||||
|
||||
public long getItemId(int position) {
|
||||
// Since a menu item's ID is optional, we'll use the position as an
|
||||
// ID for the item in the AdapterView
|
||||
return position;
|
||||
}
|
||||
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = mInflater.inflate(ITEM_LAYOUT, parent, false);
|
||||
}
|
||||
|
||||
MenuView.ItemView itemView = (MenuView.ItemView) convertView;
|
||||
if (mForceShowIcon) {
|
||||
((ListMenuItemView) convertView).setForceShowIcon(true);
|
||||
}
|
||||
itemView.initialize(getItem(position), 0);
|
||||
return convertView;
|
||||
}
|
||||
|
||||
void findExpandedIndex() {
|
||||
final MenuItemImpl expandedItem = mMenu.getExpandedItem();
|
||||
if (expandedItem != null) {
|
||||
final ArrayList<MenuItemImpl> items = mMenu.getNonActionItems();
|
||||
final int count = items.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final MenuItemImpl item = items.get(i);
|
||||
if (item == expandedItem) {
|
||||
mExpandedIndex = i;
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
mExpandedIndex = -1;
|
||||
}
|
||||
}
|
||||
|
||||
private class ExpandedIndexObserver extends DataSetObserver {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
mAdapter.findExpandedIndex();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,148 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Parcelable;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
/**
|
||||
* A MenuPresenter is responsible for building views for a Menu object.
|
||||
* It takes over some responsibility from the old style monolithic MenuBuilder class.
|
||||
*/
|
||||
public interface MenuPresenter {
|
||||
/**
|
||||
* Called by menu implementation to notify another component of open/close events.
|
||||
*/
|
||||
public interface Callback {
|
||||
/**
|
||||
* Called when a menu is closing.
|
||||
* @param menu
|
||||
* @param allMenusAreClosing
|
||||
*/
|
||||
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing);
|
||||
|
||||
/**
|
||||
* Called when a submenu opens. Useful for notifying the application
|
||||
* of menu state so that it does not attempt to hide the action bar
|
||||
* while a submenu is open or similar.
|
||||
*
|
||||
* @param subMenu Submenu currently being opened
|
||||
* @return true if the Callback will handle presenting the submenu, false if
|
||||
* the presenter should attempt to do so.
|
||||
*/
|
||||
public boolean onOpenSubMenu(MenuBuilder subMenu);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initialize this presenter for the given context and menu.
|
||||
* This method is called by MenuBuilder when a presenter is
|
||||
* added. See {@link MenuBuilder#addMenuPresenter(MenuPresenter)}
|
||||
*
|
||||
* @param context Context for this presenter; used for view creation and resource management
|
||||
* @param menu Menu to host
|
||||
*/
|
||||
public void initForMenu(Context context, MenuBuilder menu);
|
||||
|
||||
/**
|
||||
* Retrieve a MenuView to display the menu specified in
|
||||
* {@link #initForMenu(Context, Menu)}.
|
||||
*
|
||||
* @param root Intended parent of the MenuView.
|
||||
* @return A freshly created MenuView.
|
||||
*/
|
||||
public MenuView getMenuView(ViewGroup root);
|
||||
|
||||
/**
|
||||
* Update the menu UI in response to a change. Called by
|
||||
* MenuBuilder during the normal course of operation.
|
||||
*
|
||||
* @param cleared true if the menu was entirely cleared
|
||||
*/
|
||||
public void updateMenuView(boolean cleared);
|
||||
|
||||
/**
|
||||
* Set a callback object that will be notified of menu events
|
||||
* related to this specific presentation.
|
||||
* @param cb Callback that will be notified of future events
|
||||
*/
|
||||
public void setCallback(Callback cb);
|
||||
|
||||
/**
|
||||
* Called by Menu implementations to indicate that a submenu item
|
||||
* has been selected. An active Callback should be notified, and
|
||||
* if applicable the presenter should present the submenu.
|
||||
*
|
||||
* @param subMenu SubMenu being opened
|
||||
* @return true if the the event was handled, false otherwise.
|
||||
*/
|
||||
public boolean onSubMenuSelected(SubMenuBuilder subMenu);
|
||||
|
||||
/**
|
||||
* Called by Menu implementations to indicate that a menu or submenu is
|
||||
* closing. Presenter implementations should close the representation
|
||||
* of the menu indicated as necessary and notify a registered callback.
|
||||
*
|
||||
* @param menu Menu or submenu that is closing.
|
||||
* @param allMenusAreClosing True if all associated menus are closing.
|
||||
*/
|
||||
public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing);
|
||||
|
||||
/**
|
||||
* Called by Menu implementations to flag items that will be shown as actions.
|
||||
* @return true if this presenter changed the action status of any items.
|
||||
*/
|
||||
public boolean flagActionItems();
|
||||
|
||||
/**
|
||||
* Called when a menu item with a collapsable action view should expand its action view.
|
||||
*
|
||||
* @param menu Menu containing the item to be expanded
|
||||
* @param item Item to be expanded
|
||||
* @return true if this presenter expanded the action view, false otherwise.
|
||||
*/
|
||||
public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item);
|
||||
|
||||
/**
|
||||
* Called when a menu item with a collapsable action view should collapse its action view.
|
||||
*
|
||||
* @param menu Menu containing the item to be collapsed
|
||||
* @param item Item to be collapsed
|
||||
* @return true if this presenter collapsed the action view, false otherwise.
|
||||
*/
|
||||
public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item);
|
||||
|
||||
/**
|
||||
* Returns an ID for determining how to save/restore instance state.
|
||||
* @return a valid ID value.
|
||||
*/
|
||||
public int getId();
|
||||
|
||||
/**
|
||||
* Returns a Parcelable describing the current state of the presenter.
|
||||
* It will be passed to the {@link #onRestoreInstanceState(Parcelable)}
|
||||
* method of the presenter sharing the same ID later.
|
||||
* @return The saved instance state
|
||||
*/
|
||||
public Parcelable onSaveInstanceState();
|
||||
|
||||
/**
|
||||
* Supplies the previously saved instance state to be restored.
|
||||
* @param state The previously saved instance state
|
||||
*/
|
||||
public void onRestoreInstanceState(Parcelable state);
|
||||
}
|
|
@ -1,120 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
/**
|
||||
* Minimal interface for a menu view. {@link #initialize(MenuBuilder)} must be called for the
|
||||
* menu to be functional.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public interface MenuView {
|
||||
/**
|
||||
* Initializes the menu to the given menu. This should be called after the
|
||||
* view is inflated.
|
||||
*
|
||||
* @param menu The menu that this MenuView should display.
|
||||
*/
|
||||
public void initialize(MenuBuilder menu);
|
||||
|
||||
/**
|
||||
* Returns the default animations to be used for this menu when entering/exiting.
|
||||
* @return A resource ID for the default animations to be used for this menu.
|
||||
*/
|
||||
public int getWindowAnimations();
|
||||
|
||||
/**
|
||||
* Minimal interface for a menu item view. {@link #initialize(MenuItemImpl, int)} must be called
|
||||
* for the item to be functional.
|
||||
*/
|
||||
public interface ItemView {
|
||||
/**
|
||||
* Initializes with the provided MenuItemData. This should be called after the view is
|
||||
* inflated.
|
||||
* @param itemData The item that this ItemView should display.
|
||||
* @param menuType The type of this menu, one of
|
||||
* {@link MenuBuilder#TYPE_ICON}, {@link MenuBuilder#TYPE_EXPANDED},
|
||||
* {@link MenuBuilder#TYPE_DIALOG}).
|
||||
*/
|
||||
public void initialize(MenuItemImpl itemData, int menuType);
|
||||
|
||||
/**
|
||||
* Gets the item data that this view is displaying.
|
||||
* @return the item data, or null if there is not one
|
||||
*/
|
||||
public MenuItemImpl getItemData();
|
||||
|
||||
/**
|
||||
* Sets the title of the item view.
|
||||
* @param title The title to set.
|
||||
*/
|
||||
public void setTitle(CharSequence title);
|
||||
|
||||
/**
|
||||
* Sets the enabled state of the item view.
|
||||
* @param enabled Whether the item view should be enabled.
|
||||
*/
|
||||
public void setEnabled(boolean enabled);
|
||||
|
||||
/**
|
||||
* Displays the checkbox for the item view. This does not ensure the item view will be
|
||||
* checked, for that use {@link #setChecked}.
|
||||
* @param checkable Whether to display the checkbox or to hide it
|
||||
*/
|
||||
public void setCheckable(boolean checkable);
|
||||
|
||||
/**
|
||||
* Checks the checkbox for the item view. If the checkbox is hidden, it will NOT be
|
||||
* made visible, call {@link #setCheckable(boolean)} for that.
|
||||
* @param checked Whether the checkbox should be checked
|
||||
*/
|
||||
public void setChecked(boolean checked);
|
||||
|
||||
/**
|
||||
* Sets the shortcut for the item.
|
||||
* @param showShortcut Whether a shortcut should be shown(if false, the value of
|
||||
* shortcutKey should be ignored).
|
||||
* @param shortcutKey The shortcut key that should be shown on the ItemView.
|
||||
*/
|
||||
public void setShortcut(boolean showShortcut, char shortcutKey);
|
||||
|
||||
/**
|
||||
* Set the icon of this item view.
|
||||
* @param icon The icon of this item. null to hide the icon.
|
||||
*/
|
||||
public void setIcon(Drawable icon);
|
||||
|
||||
/**
|
||||
* Whether this item view prefers displaying the condensed title rather
|
||||
* than the normal title. If a condensed title is not available, the
|
||||
* normal title will be used.
|
||||
*
|
||||
* @return Whether this item view prefers displaying the condensed
|
||||
* title.
|
||||
*/
|
||||
public boolean prefersCondensedTitle();
|
||||
|
||||
/**
|
||||
* Whether this item view shows an icon.
|
||||
*
|
||||
* @return Whether this item view shows an icon.
|
||||
*/
|
||||
public boolean showsIcon();
|
||||
}
|
||||
}
|
|
@ -1,206 +0,0 @@
|
|||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import java.util.WeakHashMap;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.view.KeyEvent;
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import com.actionbarsherlock.view.SubMenu;
|
||||
|
||||
public class MenuWrapper implements Menu {
|
||||
private final android.view.Menu mNativeMenu;
|
||||
|
||||
private final WeakHashMap<android.view.MenuItem, MenuItem> mNativeMap =
|
||||
new WeakHashMap<android.view.MenuItem, MenuItem>();
|
||||
|
||||
|
||||
public MenuWrapper(android.view.Menu nativeMenu) {
|
||||
mNativeMenu = nativeMenu;
|
||||
}
|
||||
|
||||
public android.view.Menu unwrap() {
|
||||
return mNativeMenu;
|
||||
}
|
||||
|
||||
private MenuItem addInternal(android.view.MenuItem nativeItem) {
|
||||
MenuItem item = new MenuItemWrapper(nativeItem);
|
||||
mNativeMap.put(nativeItem, item);
|
||||
return item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem add(CharSequence title) {
|
||||
return addInternal(mNativeMenu.add(title));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem add(int titleRes) {
|
||||
return addInternal(mNativeMenu.add(titleRes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem add(int groupId, int itemId, int order, CharSequence title) {
|
||||
return addInternal(mNativeMenu.add(groupId, itemId, order, title));
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem add(int groupId, int itemId, int order, int titleRes) {
|
||||
return addInternal(mNativeMenu.add(groupId, itemId, order, titleRes));
|
||||
}
|
||||
|
||||
private SubMenu addInternal(android.view.SubMenu nativeSubMenu) {
|
||||
SubMenu subMenu = new SubMenuWrapper(nativeSubMenu);
|
||||
android.view.MenuItem nativeItem = nativeSubMenu.getItem();
|
||||
MenuItem item = subMenu.getItem();
|
||||
mNativeMap.put(nativeItem, item);
|
||||
return subMenu;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu addSubMenu(CharSequence title) {
|
||||
return addInternal(mNativeMenu.addSubMenu(title));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu addSubMenu(int titleRes) {
|
||||
return addInternal(mNativeMenu.addSubMenu(titleRes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu addSubMenu(int groupId, int itemId, int order, CharSequence title) {
|
||||
return addInternal(mNativeMenu.addSubMenu(groupId, itemId, order, title));
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) {
|
||||
return addInternal(mNativeMenu.addSubMenu(groupId, itemId, order, titleRes));
|
||||
}
|
||||
|
||||
@Override
|
||||
public int addIntentOptions(int groupId, int itemId, int order, ComponentName caller, Intent[] specifics, Intent intent, int flags, MenuItem[] outSpecificItems) {
|
||||
int result;
|
||||
if (outSpecificItems != null) {
|
||||
android.view.MenuItem[] nativeOutItems = new android.view.MenuItem[outSpecificItems.length];
|
||||
result = mNativeMenu.addIntentOptions(groupId, itemId, order, caller, specifics, intent, flags, nativeOutItems);
|
||||
for (int i = 0, length = outSpecificItems.length; i < length; i++) {
|
||||
outSpecificItems[i] = new MenuItemWrapper(nativeOutItems[i]);
|
||||
}
|
||||
} else {
|
||||
result = mNativeMenu.addIntentOptions(groupId, itemId, order, caller, specifics, intent, flags, null);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeItem(int id) {
|
||||
mNativeMap.remove(mNativeMenu.findItem(id));
|
||||
mNativeMenu.removeItem(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeGroup(int groupId) {
|
||||
for (int i = 0; i < mNativeMenu.size(); i++) {
|
||||
final android.view.MenuItem item = mNativeMenu.getItem(i);
|
||||
if (item.getGroupId() == groupId) {
|
||||
mNativeMap.remove(item);
|
||||
}
|
||||
}
|
||||
mNativeMenu.removeGroup(groupId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clear() {
|
||||
mNativeMap.clear();
|
||||
mNativeMenu.clear();
|
||||
}
|
||||
|
||||
public void invalidate() {
|
||||
if (mNativeMap.isEmpty()) return;
|
||||
|
||||
final WeakHashMap<android.view.MenuItem, MenuItem> menuMapCopy = new WeakHashMap<android.view.MenuItem, MenuItem>(mNativeMap.size());
|
||||
|
||||
for (int i = 0; i < mNativeMenu.size(); i++) {
|
||||
final android.view.MenuItem item = mNativeMenu.getItem(i);
|
||||
menuMapCopy.put(item, mNativeMap.get(item));
|
||||
}
|
||||
|
||||
mNativeMap.clear();
|
||||
mNativeMap.putAll(menuMapCopy);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupCheckable(int group, boolean checkable, boolean exclusive) {
|
||||
mNativeMenu.setGroupCheckable(group, checkable, exclusive);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupVisible(int group, boolean visible) {
|
||||
mNativeMenu.setGroupVisible(group, visible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setGroupEnabled(int group, boolean enabled) {
|
||||
mNativeMenu.setGroupEnabled(group, enabled);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasVisibleItems() {
|
||||
return mNativeMenu.hasVisibleItems();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem findItem(int id) {
|
||||
android.view.MenuItem nativeItem = mNativeMenu.findItem(id);
|
||||
return findItem(nativeItem);
|
||||
}
|
||||
|
||||
public MenuItem findItem(android.view.MenuItem nativeItem) {
|
||||
if (nativeItem == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
MenuItem wrapped = mNativeMap.get(nativeItem);
|
||||
if (wrapped != null) {
|
||||
return wrapped;
|
||||
}
|
||||
|
||||
return addInternal(nativeItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int size() {
|
||||
return mNativeMenu.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem getItem(int index) {
|
||||
android.view.MenuItem nativeItem = mNativeMenu.getItem(index);
|
||||
return findItem(nativeItem);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
mNativeMenu.close();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performShortcut(int keyCode, KeyEvent event, int flags) {
|
||||
return mNativeMenu.performShortcut(keyCode, event, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShortcutKey(int keyCode, KeyEvent event) {
|
||||
return mNativeMenu.isShortcutKey(keyCode, event);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performIdentifierAction(int id, int flags) {
|
||||
return mNativeMenu.performIdentifierAction(id, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQwertyMode(boolean isQwerty) {
|
||||
mNativeMenu.setQwertyMode(isQwerty);
|
||||
}
|
||||
}
|
|
@ -1,134 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
|
||||
import com.actionbarsherlock.view.Menu;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import com.actionbarsherlock.view.SubMenu;
|
||||
|
||||
/**
|
||||
* The model for a sub menu, which is an extension of the menu. Most methods are proxied to
|
||||
* the parent menu.
|
||||
*/
|
||||
public class SubMenuBuilder extends MenuBuilder implements SubMenu {
|
||||
private MenuBuilder mParentMenu;
|
||||
private MenuItemImpl mItem;
|
||||
|
||||
public SubMenuBuilder(Context context, MenuBuilder parentMenu, MenuItemImpl item) {
|
||||
super(context);
|
||||
|
||||
mParentMenu = parentMenu;
|
||||
mItem = item;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setQwertyMode(boolean isQwerty) {
|
||||
mParentMenu.setQwertyMode(isQwerty);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isQwertyMode() {
|
||||
return mParentMenu.isQwertyMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setShortcutsVisible(boolean shortcutsVisible) {
|
||||
mParentMenu.setShortcutsVisible(shortcutsVisible);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isShortcutsVisible() {
|
||||
return mParentMenu.isShortcutsVisible();
|
||||
}
|
||||
|
||||
public Menu getParentMenu() {
|
||||
return mParentMenu;
|
||||
}
|
||||
|
||||
public MenuItem getItem() {
|
||||
return mItem;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setCallback(Callback callback) {
|
||||
mParentMenu.setCallback(callback);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuBuilder getRootMenu() {
|
||||
return mParentMenu;
|
||||
}
|
||||
|
||||
@Override
|
||||
boolean dispatchMenuItemSelected(MenuBuilder menu, MenuItem item) {
|
||||
return super.dispatchMenuItemSelected(menu, item) ||
|
||||
mParentMenu.dispatchMenuItemSelected(menu, item);
|
||||
}
|
||||
|
||||
public SubMenu setIcon(Drawable icon) {
|
||||
mItem.setIcon(icon);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SubMenu setIcon(int iconRes) {
|
||||
mItem.setIcon(iconRes);
|
||||
return this;
|
||||
}
|
||||
|
||||
public SubMenu setHeaderIcon(Drawable icon) {
|
||||
return (SubMenu) super.setHeaderIconInt(icon);
|
||||
}
|
||||
|
||||
public SubMenu setHeaderIcon(int iconRes) {
|
||||
return (SubMenu) super.setHeaderIconInt(iconRes);
|
||||
}
|
||||
|
||||
public SubMenu setHeaderTitle(CharSequence title) {
|
||||
return (SubMenu) super.setHeaderTitleInt(title);
|
||||
}
|
||||
|
||||
public SubMenu setHeaderTitle(int titleRes) {
|
||||
return (SubMenu) super.setHeaderTitleInt(titleRes);
|
||||
}
|
||||
|
||||
public SubMenu setHeaderView(View view) {
|
||||
return (SubMenu) super.setHeaderViewInt(view);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean expandItemActionView(MenuItemImpl item) {
|
||||
return mParentMenu.expandItemActionView(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean collapseItemActionView(MenuItemImpl item) {
|
||||
return mParentMenu.collapseItemActionView(item);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getActionViewStatesKey() {
|
||||
final int itemId = mItem != null ? mItem.getItemId() : 0;
|
||||
if (itemId == 0) {
|
||||
return null;
|
||||
}
|
||||
return super.getActionViewStatesKey() + ":" + itemId;
|
||||
}
|
||||
}
|
|
@ -1,72 +0,0 @@
|
|||
package com.actionbarsherlock.internal.view.menu;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
import com.actionbarsherlock.view.MenuItem;
|
||||
import com.actionbarsherlock.view.SubMenu;
|
||||
|
||||
public class SubMenuWrapper extends MenuWrapper implements SubMenu {
|
||||
private final android.view.SubMenu mNativeSubMenu;
|
||||
private MenuItem mItem = null;
|
||||
|
||||
public SubMenuWrapper(android.view.SubMenu nativeSubMenu) {
|
||||
super(nativeSubMenu);
|
||||
mNativeSubMenu = nativeSubMenu;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public SubMenu setHeaderTitle(int titleRes) {
|
||||
mNativeSubMenu.setHeaderTitle(titleRes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setHeaderTitle(CharSequence title) {
|
||||
mNativeSubMenu.setHeaderTitle(title);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setHeaderIcon(int iconRes) {
|
||||
mNativeSubMenu.setHeaderIcon(iconRes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setHeaderIcon(Drawable icon) {
|
||||
mNativeSubMenu.setHeaderIcon(icon);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setHeaderView(View view) {
|
||||
mNativeSubMenu.setHeaderView(view);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void clearHeader() {
|
||||
mNativeSubMenu.clearHeader();
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setIcon(int iconRes) {
|
||||
mNativeSubMenu.setIcon(iconRes);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public SubMenu setIcon(Drawable icon) {
|
||||
mNativeSubMenu.setIcon(icon);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuItem getItem() {
|
||||
if (mItem == null) {
|
||||
mItem = new MenuItemWrapper(mNativeSubMenu.getItem());
|
||||
}
|
||||
return mItem;
|
||||
}
|
||||
}
|
|
@ -1,291 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.animation.Interpolator;
|
||||
|
||||
import com.actionbarsherlock.R;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.Animator;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.AnimatorSet;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.ObjectAnimator;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.view.NineViewGroup;
|
||||
import com.actionbarsherlock.internal.view.menu.ActionMenuPresenter;
|
||||
import com.actionbarsherlock.internal.view.menu.ActionMenuView;
|
||||
|
||||
import static com.actionbarsherlock.internal.ResourcesCompat.getResources_getBoolean;
|
||||
|
||||
public abstract class AbsActionBarView extends NineViewGroup {
|
||||
protected ActionMenuView mMenuView;
|
||||
protected ActionMenuPresenter mActionMenuPresenter;
|
||||
protected ActionBarContainer mSplitView;
|
||||
protected boolean mSplitActionBar;
|
||||
protected boolean mSplitWhenNarrow;
|
||||
protected int mContentHeight;
|
||||
|
||||
final Context mContext;
|
||||
|
||||
protected Animator mVisibilityAnim;
|
||||
protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener();
|
||||
|
||||
private static final /*Time*/Interpolator sAlphaInterpolator = new DecelerateInterpolator();
|
||||
|
||||
private static final int FADE_DURATION = 200;
|
||||
|
||||
public AbsActionBarView(Context context) {
|
||||
super(context);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public AbsActionBarView(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
public AbsActionBarView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
mContext = context;
|
||||
}
|
||||
|
||||
/*
|
||||
* Must be public so we can dispatch pre-2.2 via ActionBarImpl.
|
||||
*/
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.FROYO) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
} else if (mMenuView != null) {
|
||||
mMenuView.onConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
// Action bar can change size on configuration changes.
|
||||
// Reread the desired height from the theme-specified style.
|
||||
TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.SherlockActionBar,
|
||||
R.attr.actionBarStyle, 0);
|
||||
setContentHeight(a.getLayoutDimension(R.styleable.SherlockActionBar_height, 0));
|
||||
a.recycle();
|
||||
if (mSplitWhenNarrow) {
|
||||
setSplitActionBar(getResources_getBoolean(getContext(),
|
||||
R.bool.abs__split_action_bar_is_narrow));
|
||||
}
|
||||
if (mActionMenuPresenter != null) {
|
||||
mActionMenuPresenter.onConfigurationChanged(newConfig);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the bar should be split right now, no questions asked.
|
||||
* @param split true if the bar should split
|
||||
*/
|
||||
public void setSplitActionBar(boolean split) {
|
||||
mSplitActionBar = split;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether the bar should split if we enter a narrow screen configuration.
|
||||
* @param splitWhenNarrow true if the bar should check to split after a config change
|
||||
*/
|
||||
public void setSplitWhenNarrow(boolean splitWhenNarrow) {
|
||||
mSplitWhenNarrow = splitWhenNarrow;
|
||||
}
|
||||
|
||||
public void setContentHeight(int height) {
|
||||
mContentHeight = height;
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
public int getContentHeight() {
|
||||
return mContentHeight;
|
||||
}
|
||||
|
||||
public void setSplitView(ActionBarContainer splitView) {
|
||||
mSplitView = splitView;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Current visibility or if animating, the visibility being animated to.
|
||||
*/
|
||||
public int getAnimatedVisibility() {
|
||||
if (mVisibilityAnim != null) {
|
||||
return mVisAnimListener.mFinalVisibility;
|
||||
}
|
||||
return getVisibility();
|
||||
}
|
||||
|
||||
public void animateToVisibility(int visibility) {
|
||||
if (mVisibilityAnim != null) {
|
||||
mVisibilityAnim.cancel();
|
||||
}
|
||||
if (visibility == VISIBLE) {
|
||||
if (getVisibility() != VISIBLE) {
|
||||
setAlpha(0);
|
||||
if (mSplitView != null && mMenuView != null) {
|
||||
mMenuView.setAlpha(0);
|
||||
}
|
||||
}
|
||||
ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 1);
|
||||
anim.setDuration(FADE_DURATION);
|
||||
anim.setInterpolator(sAlphaInterpolator);
|
||||
if (mSplitView != null && mMenuView != null) {
|
||||
AnimatorSet set = new AnimatorSet();
|
||||
ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 1);
|
||||
splitAnim.setDuration(FADE_DURATION);
|
||||
set.addListener(mVisAnimListener.withFinalVisibility(visibility));
|
||||
set.play(anim).with(splitAnim);
|
||||
set.start();
|
||||
} else {
|
||||
anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
|
||||
anim.start();
|
||||
}
|
||||
} else {
|
||||
ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 0);
|
||||
anim.setDuration(FADE_DURATION);
|
||||
anim.setInterpolator(sAlphaInterpolator);
|
||||
if (mSplitView != null && mMenuView != null) {
|
||||
AnimatorSet set = new AnimatorSet();
|
||||
ObjectAnimator splitAnim = ObjectAnimator.ofFloat(mMenuView, "alpha", 0);
|
||||
splitAnim.setDuration(FADE_DURATION);
|
||||
set.addListener(mVisAnimListener.withFinalVisibility(visibility));
|
||||
set.play(anim).with(splitAnim);
|
||||
set.start();
|
||||
} else {
|
||||
anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
|
||||
anim.start();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setVisibility(int visibility) {
|
||||
if (mVisibilityAnim != null) {
|
||||
mVisibilityAnim.end();
|
||||
}
|
||||
super.setVisibility(visibility);
|
||||
}
|
||||
|
||||
public boolean showOverflowMenu() {
|
||||
if (mActionMenuPresenter != null) {
|
||||
return mActionMenuPresenter.showOverflowMenu();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public void postShowOverflowMenu() {
|
||||
post(new Runnable() {
|
||||
public void run() {
|
||||
showOverflowMenu();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public boolean hideOverflowMenu() {
|
||||
if (mActionMenuPresenter != null) {
|
||||
return mActionMenuPresenter.hideOverflowMenu();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isOverflowMenuShowing() {
|
||||
if (mActionMenuPresenter != null) {
|
||||
return mActionMenuPresenter.isOverflowMenuShowing();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public boolean isOverflowReserved() {
|
||||
return mActionMenuPresenter != null && mActionMenuPresenter.isOverflowReserved();
|
||||
}
|
||||
|
||||
public void dismissPopupMenus() {
|
||||
if (mActionMenuPresenter != null) {
|
||||
mActionMenuPresenter.dismissPopupMenus();
|
||||
}
|
||||
}
|
||||
|
||||
protected int measureChildView(View child, int availableWidth, int childSpecHeight,
|
||||
int spacing) {
|
||||
child.measure(MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
|
||||
childSpecHeight);
|
||||
|
||||
availableWidth -= child.getMeasuredWidth();
|
||||
availableWidth -= spacing;
|
||||
|
||||
return Math.max(0, availableWidth);
|
||||
}
|
||||
|
||||
protected int positionChild(View child, int x, int y, int contentHeight) {
|
||||
int childWidth = child.getMeasuredWidth();
|
||||
int childHeight = child.getMeasuredHeight();
|
||||
int childTop = y + (contentHeight - childHeight) / 2;
|
||||
|
||||
child.layout(x, childTop, x + childWidth, childTop + childHeight);
|
||||
|
||||
return childWidth;
|
||||
}
|
||||
|
||||
protected int positionChildInverse(View child, int x, int y, int contentHeight) {
|
||||
int childWidth = child.getMeasuredWidth();
|
||||
int childHeight = child.getMeasuredHeight();
|
||||
int childTop = y + (contentHeight - childHeight) / 2;
|
||||
|
||||
child.layout(x - childWidth, childTop, x, childTop + childHeight);
|
||||
|
||||
return childWidth;
|
||||
}
|
||||
|
||||
protected class VisibilityAnimListener implements Animator.AnimatorListener {
|
||||
private boolean mCanceled = false;
|
||||
int mFinalVisibility;
|
||||
|
||||
public VisibilityAnimListener withFinalVisibility(int visibility) {
|
||||
mFinalVisibility = visibility;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
setVisibility(VISIBLE);
|
||||
mVisibilityAnim = animation;
|
||||
mCanceled = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (mCanceled) return;
|
||||
|
||||
mVisibilityAnim = null;
|
||||
setVisibility(mFinalVisibility);
|
||||
if (mSplitView != null && mMenuView != null) {
|
||||
mMenuView.setVisibility(mFinalVisibility);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
mCanceled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,251 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import com.actionbarsherlock.R;
|
||||
import com.actionbarsherlock.app.ActionBar;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.widget.NineFrameLayout;
|
||||
|
||||
/**
|
||||
* This class acts as a container for the action bar view and action mode context views.
|
||||
* It applies special styles as needed to help handle animated transitions between them.
|
||||
* @hide
|
||||
*/
|
||||
public class ActionBarContainer extends NineFrameLayout {
|
||||
private boolean mIsTransitioning;
|
||||
private View mTabContainer;
|
||||
private ActionBarView mActionBarView;
|
||||
|
||||
private Drawable mBackground;
|
||||
private Drawable mStackedBackground;
|
||||
private Drawable mSplitBackground;
|
||||
private boolean mIsSplit;
|
||||
private boolean mIsStacked;
|
||||
|
||||
public ActionBarContainer(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public ActionBarContainer(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
setBackgroundDrawable(null);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs,
|
||||
R.styleable.SherlockActionBar);
|
||||
mBackground = a.getDrawable(R.styleable.SherlockActionBar_background);
|
||||
mStackedBackground = a.getDrawable(
|
||||
R.styleable.SherlockActionBar_backgroundStacked);
|
||||
|
||||
//Fix for issue #379
|
||||
if (mStackedBackground instanceof ColorDrawable && Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
|
||||
mStackedBackground = new IcsColorDrawable((ColorDrawable) mStackedBackground);
|
||||
}
|
||||
|
||||
if (getId() == R.id.abs__split_action_bar) {
|
||||
mIsSplit = true;
|
||||
mSplitBackground = a.getDrawable(
|
||||
R.styleable.SherlockActionBar_backgroundSplit);
|
||||
}
|
||||
a.recycle();
|
||||
|
||||
setWillNotDraw(mIsSplit ? mSplitBackground == null :
|
||||
mBackground == null && mStackedBackground == null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinishInflate() {
|
||||
super.onFinishInflate();
|
||||
mActionBarView = (ActionBarView) findViewById(R.id.abs__action_bar);
|
||||
}
|
||||
|
||||
public void setPrimaryBackground(Drawable bg) {
|
||||
mBackground = bg;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setStackedBackground(Drawable bg) {
|
||||
mStackedBackground = bg;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
public void setSplitBackground(Drawable bg) {
|
||||
mSplitBackground = bg;
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the action bar into a "transitioning" state. While transitioning
|
||||
* the bar will block focus and touch from all of its descendants. This
|
||||
* prevents the user from interacting with the bar while it is animating
|
||||
* in or out.
|
||||
*
|
||||
* @param isTransitioning true if the bar is currently transitioning, false otherwise.
|
||||
*/
|
||||
public void setTransitioning(boolean isTransitioning) {
|
||||
mIsTransitioning = isTransitioning;
|
||||
setDescendantFocusability(isTransitioning ? FOCUS_BLOCK_DESCENDANTS
|
||||
: FOCUS_AFTER_DESCENDANTS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onInterceptTouchEvent(MotionEvent ev) {
|
||||
return mIsTransitioning || super.onInterceptTouchEvent(ev);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
super.onTouchEvent(ev);
|
||||
|
||||
// An action bar always eats touch events.
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean onHoverEvent(MotionEvent ev) {
|
||||
super.onHoverEvent(ev);
|
||||
|
||||
// An action bar always eats hover events.
|
||||
return true;
|
||||
}
|
||||
|
||||
public void setTabContainer(ScrollingTabContainerView tabView) {
|
||||
if (mTabContainer != null) {
|
||||
removeView(mTabContainer);
|
||||
}
|
||||
mTabContainer = tabView;
|
||||
if (tabView != null) {
|
||||
addView(tabView);
|
||||
final ViewGroup.LayoutParams lp = tabView.getLayoutParams();
|
||||
lp.width = LayoutParams.MATCH_PARENT;
|
||||
lp.height = LayoutParams.WRAP_CONTENT;
|
||||
tabView.setAllowCollapse(false);
|
||||
}
|
||||
}
|
||||
|
||||
public View getTabContainer() {
|
||||
return mTabContainer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDraw(Canvas canvas) {
|
||||
if (getWidth() == 0 || getHeight() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (mIsSplit) {
|
||||
if (mSplitBackground != null) mSplitBackground.draw(canvas);
|
||||
} else {
|
||||
if (mBackground != null) {
|
||||
mBackground.draw(canvas);
|
||||
}
|
||||
if (mStackedBackground != null && mIsStacked) {
|
||||
mStackedBackground.draw(canvas);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//This causes the animation reflection to fail on pre-HC platforms
|
||||
//@Override
|
||||
//public android.view.ActionMode startActionModeForChild(View child, android.view.ActionMode.Callback callback) {
|
||||
// // No starting an action mode for an action bar child! (Where would it go?)
|
||||
// return null;
|
||||
//}
|
||||
|
||||
@Override
|
||||
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
if (mActionBarView == null) return;
|
||||
|
||||
final LayoutParams lp = (LayoutParams) mActionBarView.getLayoutParams();
|
||||
final int actionBarViewHeight = mActionBarView.isCollapsed() ? 0 :
|
||||
mActionBarView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
|
||||
|
||||
if (mTabContainer != null && mTabContainer.getVisibility() != GONE) {
|
||||
final int mode = MeasureSpec.getMode(heightMeasureSpec);
|
||||
if (mode == MeasureSpec.AT_MOST) {
|
||||
final int maxHeight = MeasureSpec.getSize(heightMeasureSpec);
|
||||
setMeasuredDimension(getMeasuredWidth(),
|
||||
Math.min(actionBarViewHeight + mTabContainer.getMeasuredHeight(),
|
||||
maxHeight));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
super.onLayout(changed, l, t, r, b);
|
||||
|
||||
final boolean hasTabs = mTabContainer != null && mTabContainer.getVisibility() != GONE;
|
||||
|
||||
if (mTabContainer != null && mTabContainer.getVisibility() != GONE) {
|
||||
final int containerHeight = getMeasuredHeight();
|
||||
final int tabHeight = mTabContainer.getMeasuredHeight();
|
||||
|
||||
if ((mActionBarView.getDisplayOptions() & ActionBar.DISPLAY_SHOW_HOME) == 0) {
|
||||
// Not showing home, put tabs on top.
|
||||
final int count = getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
|
||||
if (child == mTabContainer) continue;
|
||||
|
||||
if (!mActionBarView.isCollapsed()) {
|
||||
child.offsetTopAndBottom(tabHeight);
|
||||
}
|
||||
}
|
||||
mTabContainer.layout(l, 0, r, tabHeight);
|
||||
} else {
|
||||
mTabContainer.layout(l, containerHeight - tabHeight, r, containerHeight);
|
||||
}
|
||||
}
|
||||
|
||||
boolean needsInvalidate = false;
|
||||
if (mIsSplit) {
|
||||
if (mSplitBackground != null) {
|
||||
mSplitBackground.setBounds(0, 0, getMeasuredWidth(), getMeasuredHeight());
|
||||
needsInvalidate = true;
|
||||
}
|
||||
} else {
|
||||
if (mBackground != null) {
|
||||
mBackground.setBounds(mActionBarView.getLeft(), mActionBarView.getTop(),
|
||||
mActionBarView.getRight(), mActionBarView.getBottom());
|
||||
needsInvalidate = true;
|
||||
}
|
||||
if ((mIsStacked = hasTabs && mStackedBackground != null)) {
|
||||
mStackedBackground.setBounds(mTabContainer.getLeft(), mTabContainer.getTop(),
|
||||
mTabContainer.getRight(), mTabContainer.getBottom());
|
||||
needsInvalidate = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (needsInvalidate) {
|
||||
invalidate();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,518 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.TextUtils;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.accessibility.AccessibilityEvent;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.actionbarsherlock.R;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.Animator;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.Animator.AnimatorListener;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.AnimatorSet;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.ObjectAnimator;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.view.animation.AnimatorProxy;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.widget.NineLinearLayout;
|
||||
import com.actionbarsherlock.internal.view.menu.ActionMenuPresenter;
|
||||
import com.actionbarsherlock.internal.view.menu.ActionMenuView;
|
||||
import com.actionbarsherlock.internal.view.menu.MenuBuilder;
|
||||
import com.actionbarsherlock.view.ActionMode;
|
||||
|
||||
/**
|
||||
* @hide
|
||||
*/
|
||||
public class ActionBarContextView extends AbsActionBarView implements AnimatorListener {
|
||||
//UNUSED private static final String TAG = "ActionBarContextView";
|
||||
|
||||
private CharSequence mTitle;
|
||||
private CharSequence mSubtitle;
|
||||
|
||||
private NineLinearLayout mClose;
|
||||
private View mCustomView;
|
||||
private LinearLayout mTitleLayout;
|
||||
private TextView mTitleView;
|
||||
private TextView mSubtitleView;
|
||||
private int mTitleStyleRes;
|
||||
private int mSubtitleStyleRes;
|
||||
private Drawable mSplitBackground;
|
||||
|
||||
private Animator mCurrentAnimation;
|
||||
private boolean mAnimateInOnLayout;
|
||||
private int mAnimationMode;
|
||||
|
||||
private static final int ANIMATE_IDLE = 0;
|
||||
private static final int ANIMATE_IN = 1;
|
||||
private static final int ANIMATE_OUT = 2;
|
||||
|
||||
public ActionBarContextView(Context context) {
|
||||
this(context, null);
|
||||
}
|
||||
|
||||
public ActionBarContextView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, R.attr.actionModeStyle);
|
||||
}
|
||||
|
||||
public ActionBarContextView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SherlockActionMode, defStyle, 0);
|
||||
setBackgroundDrawable(a.getDrawable(
|
||||
R.styleable.SherlockActionMode_background));
|
||||
mTitleStyleRes = a.getResourceId(
|
||||
R.styleable.SherlockActionMode_titleTextStyle, 0);
|
||||
mSubtitleStyleRes = a.getResourceId(
|
||||
R.styleable.SherlockActionMode_subtitleTextStyle, 0);
|
||||
|
||||
mContentHeight = a.getLayoutDimension(
|
||||
R.styleable.SherlockActionMode_height, 0);
|
||||
|
||||
mSplitBackground = a.getDrawable(
|
||||
R.styleable.SherlockActionMode_backgroundSplit);
|
||||
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
if (mActionMenuPresenter != null) {
|
||||
mActionMenuPresenter.hideOverflowMenu();
|
||||
mActionMenuPresenter.hideSubMenus();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSplitActionBar(boolean split) {
|
||||
if (mSplitActionBar != split) {
|
||||
if (mActionMenuPresenter != null) {
|
||||
// Mode is already active; move everything over and adjust the menu itself.
|
||||
final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
|
||||
LayoutParams.MATCH_PARENT);
|
||||
if (!split) {
|
||||
mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
|
||||
mMenuView.setBackgroundDrawable(null);
|
||||
final ViewGroup oldParent = (ViewGroup) mMenuView.getParent();
|
||||
if (oldParent != null) oldParent.removeView(mMenuView);
|
||||
addView(mMenuView, layoutParams);
|
||||
} else {
|
||||
// Allow full screen width in split mode.
|
||||
mActionMenuPresenter.setWidthLimit(
|
||||
getContext().getResources().getDisplayMetrics().widthPixels, true);
|
||||
// No limit to the item count; use whatever will fit.
|
||||
mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);
|
||||
// Span the whole width
|
||||
layoutParams.width = LayoutParams.MATCH_PARENT;
|
||||
layoutParams.height = mContentHeight;
|
||||
mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
|
||||
mMenuView.setBackgroundDrawable(mSplitBackground);
|
||||
final ViewGroup oldParent = (ViewGroup) mMenuView.getParent();
|
||||
if (oldParent != null) oldParent.removeView(mMenuView);
|
||||
mSplitView.addView(mMenuView, layoutParams);
|
||||
}
|
||||
}
|
||||
super.setSplitActionBar(split);
|
||||
}
|
||||
}
|
||||
|
||||
public void setContentHeight(int height) {
|
||||
mContentHeight = height;
|
||||
}
|
||||
|
||||
public void setCustomView(View view) {
|
||||
if (mCustomView != null) {
|
||||
removeView(mCustomView);
|
||||
}
|
||||
mCustomView = view;
|
||||
if (mTitleLayout != null) {
|
||||
removeView(mTitleLayout);
|
||||
mTitleLayout = null;
|
||||
}
|
||||
if (view != null) {
|
||||
addView(view);
|
||||
}
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
public void setTitle(CharSequence title) {
|
||||
mTitle = title;
|
||||
initTitle();
|
||||
}
|
||||
|
||||
public void setSubtitle(CharSequence subtitle) {
|
||||
mSubtitle = subtitle;
|
||||
initTitle();
|
||||
}
|
||||
|
||||
public CharSequence getTitle() {
|
||||
return mTitle;
|
||||
}
|
||||
|
||||
public CharSequence getSubtitle() {
|
||||
return mSubtitle;
|
||||
}
|
||||
|
||||
private void initTitle() {
|
||||
if (mTitleLayout == null) {
|
||||
LayoutInflater inflater = LayoutInflater.from(getContext());
|
||||
inflater.inflate(R.layout.abs__action_bar_title_item, this);
|
||||
mTitleLayout = (LinearLayout) getChildAt(getChildCount() - 1);
|
||||
mTitleView = (TextView) mTitleLayout.findViewById(R.id.abs__action_bar_title);
|
||||
mSubtitleView = (TextView) mTitleLayout.findViewById(R.id.abs__action_bar_subtitle);
|
||||
if (mTitleStyleRes != 0) {
|
||||
mTitleView.setTextAppearance(mContext, mTitleStyleRes);
|
||||
}
|
||||
if (mSubtitleStyleRes != 0) {
|
||||
mSubtitleView.setTextAppearance(mContext, mSubtitleStyleRes);
|
||||
}
|
||||
}
|
||||
|
||||
mTitleView.setText(mTitle);
|
||||
mSubtitleView.setText(mSubtitle);
|
||||
|
||||
final boolean hasTitle = !TextUtils.isEmpty(mTitle);
|
||||
final boolean hasSubtitle = !TextUtils.isEmpty(mSubtitle);
|
||||
mSubtitleView.setVisibility(hasSubtitle ? VISIBLE : GONE);
|
||||
mTitleLayout.setVisibility(hasTitle || hasSubtitle ? VISIBLE : GONE);
|
||||
if (mTitleLayout.getParent() == null) {
|
||||
addView(mTitleLayout);
|
||||
}
|
||||
}
|
||||
|
||||
public void initForMode(final ActionMode mode) {
|
||||
if (mClose == null) {
|
||||
LayoutInflater inflater = LayoutInflater.from(mContext);
|
||||
mClose = (NineLinearLayout)inflater.inflate(R.layout.abs__action_mode_close_item, this, false);
|
||||
addView(mClose);
|
||||
} else if (mClose.getParent() == null) {
|
||||
addView(mClose);
|
||||
}
|
||||
|
||||
View closeButton = mClose.findViewById(R.id.abs__action_mode_close_button);
|
||||
closeButton.setOnClickListener(new OnClickListener() {
|
||||
public void onClick(View v) {
|
||||
mode.finish();
|
||||
}
|
||||
});
|
||||
|
||||
final MenuBuilder menu = (MenuBuilder) mode.getMenu();
|
||||
if (mActionMenuPresenter != null) {
|
||||
mActionMenuPresenter.dismissPopupMenus();
|
||||
}
|
||||
mActionMenuPresenter = new ActionMenuPresenter(mContext);
|
||||
mActionMenuPresenter.setReserveOverflow(true);
|
||||
|
||||
final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
|
||||
LayoutParams.MATCH_PARENT);
|
||||
if (!mSplitActionBar) {
|
||||
menu.addMenuPresenter(mActionMenuPresenter);
|
||||
mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
|
||||
mMenuView.setBackgroundDrawable(null);
|
||||
addView(mMenuView, layoutParams);
|
||||
} else {
|
||||
// Allow full screen width in split mode.
|
||||
mActionMenuPresenter.setWidthLimit(
|
||||
getContext().getResources().getDisplayMetrics().widthPixels, true);
|
||||
// No limit to the item count; use whatever will fit.
|
||||
mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);
|
||||
// Span the whole width
|
||||
layoutParams.width = LayoutParams.MATCH_PARENT;
|
||||
layoutParams.height = mContentHeight;
|
||||
menu.addMenuPresenter(mActionMenuPresenter);
|
||||
mMenuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
|
||||
mMenuView.setBackgroundDrawable(mSplitBackground);
|
||||
mSplitView.addView(mMenuView, layoutParams);
|
||||
}
|
||||
|
||||
mAnimateInOnLayout = true;
|
||||
}
|
||||
|
||||
public void closeMode() {
|
||||
if (mAnimationMode == ANIMATE_OUT) {
|
||||
// Called again during close; just finish what we were doing.
|
||||
return;
|
||||
}
|
||||
if (mClose == null) {
|
||||
killMode();
|
||||
return;
|
||||
}
|
||||
|
||||
finishAnimation();
|
||||
mAnimationMode = ANIMATE_OUT;
|
||||
mCurrentAnimation = makeOutAnimation();
|
||||
mCurrentAnimation.start();
|
||||
}
|
||||
|
||||
private void finishAnimation() {
|
||||
final Animator a = mCurrentAnimation;
|
||||
if (a != null) {
|
||||
mCurrentAnimation = null;
|
||||
a.end();
|
||||
}
|
||||
}
|
||||
|
||||
public void killMode() {
|
||||
finishAnimation();
|
||||
removeAllViews();
|
||||
if (mSplitView != null) {
|
||||
mSplitView.removeView(mMenuView);
|
||||
}
|
||||
mCustomView = null;
|
||||
mMenuView = null;
|
||||
mAnimateInOnLayout = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean showOverflowMenu() {
|
||||
if (mActionMenuPresenter != null) {
|
||||
return mActionMenuPresenter.showOverflowMenu();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hideOverflowMenu() {
|
||||
if (mActionMenuPresenter != null) {
|
||||
return mActionMenuPresenter.hideOverflowMenu();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isOverflowMenuShowing() {
|
||||
if (mActionMenuPresenter != null) {
|
||||
return mActionMenuPresenter.isOverflowMenuShowing();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
|
||||
// Used by custom views if they don't supply layout params. Everything else
|
||||
// added to an ActionBarContextView should have them already.
|
||||
return new MarginLayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
|
||||
return new MarginLayoutParams(getContext(), attrs);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
|
||||
if (widthMode != MeasureSpec.EXACTLY) {
|
||||
throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
|
||||
"with android:layout_width=\"match_parent\" (or fill_parent)");
|
||||
}
|
||||
|
||||
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
|
||||
if (heightMode == MeasureSpec.UNSPECIFIED) {
|
||||
throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
|
||||
"with android:layout_height=\"wrap_content\"");
|
||||
}
|
||||
|
||||
final int contentWidth = MeasureSpec.getSize(widthMeasureSpec);
|
||||
|
||||
int maxHeight = mContentHeight > 0 ?
|
||||
mContentHeight : MeasureSpec.getSize(heightMeasureSpec);
|
||||
|
||||
final int verticalPadding = getPaddingTop() + getPaddingBottom();
|
||||
int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight();
|
||||
final int height = maxHeight - verticalPadding;
|
||||
final int childSpecHeight = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
|
||||
|
||||
if (mClose != null) {
|
||||
availableWidth = measureChildView(mClose, availableWidth, childSpecHeight, 0);
|
||||
MarginLayoutParams lp = (MarginLayoutParams) mClose.getLayoutParams();
|
||||
availableWidth -= lp.leftMargin + lp.rightMargin;
|
||||
}
|
||||
|
||||
if (mMenuView != null && mMenuView.getParent() == this) {
|
||||
availableWidth = measureChildView(mMenuView, availableWidth,
|
||||
childSpecHeight, 0);
|
||||
}
|
||||
|
||||
if (mTitleLayout != null && mCustomView == null) {
|
||||
availableWidth = measureChildView(mTitleLayout, availableWidth, childSpecHeight, 0);
|
||||
}
|
||||
|
||||
if (mCustomView != null) {
|
||||
ViewGroup.LayoutParams lp = mCustomView.getLayoutParams();
|
||||
final int customWidthMode = lp.width != LayoutParams.WRAP_CONTENT ?
|
||||
MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
|
||||
final int customWidth = lp.width >= 0 ?
|
||||
Math.min(lp.width, availableWidth) : availableWidth;
|
||||
final int customHeightMode = lp.height != LayoutParams.WRAP_CONTENT ?
|
||||
MeasureSpec.EXACTLY : MeasureSpec.AT_MOST;
|
||||
final int customHeight = lp.height >= 0 ?
|
||||
Math.min(lp.height, height) : height;
|
||||
mCustomView.measure(MeasureSpec.makeMeasureSpec(customWidth, customWidthMode),
|
||||
MeasureSpec.makeMeasureSpec(customHeight, customHeightMode));
|
||||
}
|
||||
|
||||
if (mContentHeight <= 0) {
|
||||
int measuredHeight = 0;
|
||||
final int count = getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
View v = getChildAt(i);
|
||||
int paddedViewHeight = v.getMeasuredHeight() + verticalPadding;
|
||||
if (paddedViewHeight > measuredHeight) {
|
||||
measuredHeight = paddedViewHeight;
|
||||
}
|
||||
}
|
||||
setMeasuredDimension(contentWidth, measuredHeight);
|
||||
} else {
|
||||
setMeasuredDimension(contentWidth, maxHeight);
|
||||
}
|
||||
}
|
||||
|
||||
private Animator makeInAnimation() {
|
||||
mClose.setTranslationX(-mClose.getWidth() -
|
||||
((MarginLayoutParams) mClose.getLayoutParams()).leftMargin);
|
||||
ObjectAnimator buttonAnimator = ObjectAnimator.ofFloat(mClose, "translationX", 0);
|
||||
buttonAnimator.setDuration(200);
|
||||
buttonAnimator.addListener(this);
|
||||
buttonAnimator.setInterpolator(new DecelerateInterpolator());
|
||||
|
||||
AnimatorSet set = new AnimatorSet();
|
||||
AnimatorSet.Builder b = set.play(buttonAnimator);
|
||||
|
||||
if (mMenuView != null) {
|
||||
final int count = mMenuView.getChildCount();
|
||||
if (count > 0) {
|
||||
for (int i = count - 1, j = 0; i >= 0; i--, j++) {
|
||||
AnimatorProxy child = AnimatorProxy.wrap(mMenuView.getChildAt(i));
|
||||
child.setScaleY(0);
|
||||
ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 0, 1);
|
||||
a.setDuration(100);
|
||||
a.setStartDelay(j * 70);
|
||||
b.with(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
private Animator makeOutAnimation() {
|
||||
ObjectAnimator buttonAnimator = ObjectAnimator.ofFloat(mClose, "translationX",
|
||||
-mClose.getWidth() - ((MarginLayoutParams) mClose.getLayoutParams()).leftMargin);
|
||||
buttonAnimator.setDuration(200);
|
||||
buttonAnimator.addListener(this);
|
||||
buttonAnimator.setInterpolator(new DecelerateInterpolator());
|
||||
|
||||
AnimatorSet set = new AnimatorSet();
|
||||
AnimatorSet.Builder b = set.play(buttonAnimator);
|
||||
|
||||
if (mMenuView != null) {
|
||||
final int count = mMenuView.getChildCount();
|
||||
if (count > 0) {
|
||||
for (int i = 0; i < 0; i++) {
|
||||
AnimatorProxy child = AnimatorProxy.wrap(mMenuView.getChildAt(i));
|
||||
child.setScaleY(0);
|
||||
ObjectAnimator a = ObjectAnimator.ofFloat(child, "scaleY", 0);
|
||||
a.setDuration(100);
|
||||
a.setStartDelay(i * 70);
|
||||
b.with(a);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
int x = getPaddingLeft();
|
||||
final int y = getPaddingTop();
|
||||
final int contentHeight = b - t - getPaddingTop() - getPaddingBottom();
|
||||
|
||||
if (mClose != null && mClose.getVisibility() != GONE) {
|
||||
MarginLayoutParams lp = (MarginLayoutParams) mClose.getLayoutParams();
|
||||
x += lp.leftMargin;
|
||||
x += positionChild(mClose, x, y, contentHeight);
|
||||
x += lp.rightMargin;
|
||||
|
||||
if (mAnimateInOnLayout) {
|
||||
mAnimationMode = ANIMATE_IN;
|
||||
mCurrentAnimation = makeInAnimation();
|
||||
mCurrentAnimation.start();
|
||||
mAnimateInOnLayout = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (mTitleLayout != null && mCustomView == null) {
|
||||
x += positionChild(mTitleLayout, x, y, contentHeight);
|
||||
}
|
||||
|
||||
if (mCustomView != null) {
|
||||
x += positionChild(mCustomView, x, y, contentHeight);
|
||||
}
|
||||
|
||||
x = r - l - getPaddingRight();
|
||||
|
||||
if (mMenuView != null) {
|
||||
x -= positionChildInverse(mMenuView, x, y, contentHeight);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (mAnimationMode == ANIMATE_OUT) {
|
||||
killMode();
|
||||
}
|
||||
mAnimationMode = ANIMATE_IDLE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldDelayChildPressedState() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInitializeAccessibilityEvent(AccessibilityEvent event) {
|
||||
if (event.getEventType() == AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED) {
|
||||
// Action mode started
|
||||
//TODO event.setSource(this);
|
||||
event.setClassName(getClass().getName());
|
||||
event.setPackageName(getContext().getPackageName());
|
||||
event.setContentDescription(mTitle);
|
||||
} else {
|
||||
//TODO super.onInitializeAccessibilityEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,45 +0,0 @@
|
|||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import java.util.Locale;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.Button;
|
||||
|
||||
public class CapitalizingButton extends Button {
|
||||
private static final boolean SANS_ICE_CREAM = Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH;
|
||||
private static final boolean IS_GINGERBREAD = Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD;
|
||||
|
||||
private static final int[] R_styleable_Button = new int[] {
|
||||
android.R.attr.textAllCaps
|
||||
};
|
||||
private static final int R_styleable_Button_textAllCaps = 0;
|
||||
|
||||
private boolean mAllCaps;
|
||||
|
||||
public CapitalizingButton(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R_styleable_Button);
|
||||
mAllCaps = a.getBoolean(R_styleable_Button_textAllCaps, true);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
public void setTextCompat(CharSequence text) {
|
||||
if (SANS_ICE_CREAM && mAllCaps && text != null) {
|
||||
if (IS_GINGERBREAD) {
|
||||
try {
|
||||
setText(text.toString().toUpperCase(Locale.ROOT));
|
||||
} catch (NoSuchFieldError e) {
|
||||
//Some manufacturer broke Locale.ROOT. See #572.
|
||||
setText(text.toString().toUpperCase());
|
||||
}
|
||||
} else {
|
||||
setText(text.toString().toUpperCase());
|
||||
}
|
||||
} else {
|
||||
setText(text);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,50 +0,0 @@
|
|||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.widget.TextView;
|
||||
|
||||
import java.util.Locale;
|
||||
|
||||
public class CapitalizingTextView extends TextView {
|
||||
private static final boolean SANS_ICE_CREAM = Build.VERSION.SDK_INT < Build.VERSION_CODES.ICE_CREAM_SANDWICH;
|
||||
private static final boolean IS_GINGERBREAD = Build.VERSION.SDK_INT >= Build.VERSION_CODES.GINGERBREAD;
|
||||
|
||||
private static final int[] R_styleable_TextView = new int[] {
|
||||
android.R.attr.textAllCaps
|
||||
};
|
||||
private static final int R_styleable_TextView_textAllCaps = 0;
|
||||
|
||||
private boolean mAllCaps;
|
||||
|
||||
public CapitalizingTextView(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public CapitalizingTextView(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, R_styleable_TextView, defStyle, 0);
|
||||
mAllCaps = a.getBoolean(R_styleable_TextView_textAllCaps, true);
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
public void setTextCompat(CharSequence text) {
|
||||
if (SANS_ICE_CREAM && mAllCaps && text != null) {
|
||||
if (IS_GINGERBREAD) {
|
||||
try {
|
||||
setText(text.toString().toUpperCase(Locale.ROOT));
|
||||
} catch (NoSuchFieldError e) {
|
||||
//Some manufacturer broke Locale.ROOT. See #572.
|
||||
setText(text.toString().toUpperCase());
|
||||
}
|
||||
} else {
|
||||
setText(text.toString().toUpperCase());
|
||||
}
|
||||
} else {
|
||||
setText(text);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,30 +0,0 @@
|
|||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import android.view.View;
|
||||
import android.widget.FrameLayout;
|
||||
import com.actionbarsherlock.view.CollapsibleActionView;
|
||||
|
||||
/**
|
||||
* Wraps an ABS collapsible action view in a native container that delegates the calls.
|
||||
*/
|
||||
public class CollapsibleActionViewWrapper extends FrameLayout implements android.view.CollapsibleActionView {
|
||||
private final CollapsibleActionView child;
|
||||
|
||||
public CollapsibleActionViewWrapper(View child) {
|
||||
super(child.getContext());
|
||||
this.child = (CollapsibleActionView) child;
|
||||
addView(child);
|
||||
}
|
||||
|
||||
@Override public void onActionViewExpanded() {
|
||||
child.onActionViewExpanded();
|
||||
}
|
||||
|
||||
@Override public void onActionViewCollapsed() {
|
||||
child.onActionViewCollapsed();
|
||||
}
|
||||
|
||||
public View unwrap() {
|
||||
return getChildAt(0);
|
||||
}
|
||||
}
|
|
@ -1,479 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.database.DataSetObserver;
|
||||
import android.graphics.Rect;
|
||||
import android.os.Build;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.SpinnerAdapter;
|
||||
|
||||
/**
|
||||
* An abstract base class for spinner widgets. SDK users will probably not
|
||||
* need to use this class.
|
||||
*
|
||||
* @attr ref android.R.styleable#AbsSpinner_entries
|
||||
*/
|
||||
public abstract class IcsAbsSpinner extends IcsAdapterView<SpinnerAdapter> {
|
||||
private static final boolean IS_HONEYCOMB = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
|
||||
|
||||
SpinnerAdapter mAdapter;
|
||||
|
||||
int mHeightMeasureSpec;
|
||||
int mWidthMeasureSpec;
|
||||
boolean mBlockLayoutRequests;
|
||||
|
||||
int mSelectionLeftPadding = 0;
|
||||
int mSelectionTopPadding = 0;
|
||||
int mSelectionRightPadding = 0;
|
||||
int mSelectionBottomPadding = 0;
|
||||
final Rect mSpinnerPadding = new Rect();
|
||||
|
||||
final RecycleBin mRecycler = new RecycleBin();
|
||||
private DataSetObserver mDataSetObserver;
|
||||
|
||||
/** Temporary frame to hold a child View's frame rectangle */
|
||||
private Rect mTouchFrame;
|
||||
|
||||
public IcsAbsSpinner(Context context) {
|
||||
super(context);
|
||||
initAbsSpinner();
|
||||
}
|
||||
|
||||
public IcsAbsSpinner(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, 0);
|
||||
}
|
||||
|
||||
public IcsAbsSpinner(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
initAbsSpinner();
|
||||
|
||||
/*
|
||||
TypedArray a = context.obtainStyledAttributes(attrs,
|
||||
com.android.internal.R.styleable.AbsSpinner, defStyle, 0);
|
||||
|
||||
CharSequence[] entries = a.getTextArray(R.styleable.AbsSpinner_entries);
|
||||
if (entries != null) {
|
||||
ArrayAdapter<CharSequence> adapter =
|
||||
new ArrayAdapter<CharSequence>(context,
|
||||
R.layout.simple_spinner_item, entries);
|
||||
adapter.setDropDownViewResource(R.layout.simple_spinner_dropdown_item);
|
||||
setAdapter(adapter);
|
||||
}
|
||||
|
||||
a.recycle();
|
||||
*/
|
||||
}
|
||||
|
||||
/**
|
||||
* Common code for different constructor flavors
|
||||
*/
|
||||
private void initAbsSpinner() {
|
||||
setFocusable(true);
|
||||
setWillNotDraw(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* The Adapter is used to provide the data which backs this Spinner.
|
||||
* It also provides methods to transform spinner items based on their position
|
||||
* relative to the selected item.
|
||||
* @param adapter The SpinnerAdapter to use for this Spinner
|
||||
*/
|
||||
@Override
|
||||
public void setAdapter(SpinnerAdapter adapter) {
|
||||
if (null != mAdapter) {
|
||||
mAdapter.unregisterDataSetObserver(mDataSetObserver);
|
||||
resetList();
|
||||
}
|
||||
|
||||
mAdapter = adapter;
|
||||
|
||||
mOldSelectedPosition = INVALID_POSITION;
|
||||
mOldSelectedRowId = INVALID_ROW_ID;
|
||||
|
||||
if (mAdapter != null) {
|
||||
mOldItemCount = mItemCount;
|
||||
mItemCount = mAdapter.getCount();
|
||||
checkFocus();
|
||||
|
||||
mDataSetObserver = new AdapterDataSetObserver();
|
||||
mAdapter.registerDataSetObserver(mDataSetObserver);
|
||||
|
||||
int position = mItemCount > 0 ? 0 : INVALID_POSITION;
|
||||
|
||||
setSelectedPositionInt(position);
|
||||
setNextSelectedPositionInt(position);
|
||||
|
||||
if (mItemCount == 0) {
|
||||
// Nothing selected
|
||||
checkSelectionChanged();
|
||||
}
|
||||
|
||||
} else {
|
||||
checkFocus();
|
||||
resetList();
|
||||
// Nothing selected
|
||||
checkSelectionChanged();
|
||||
}
|
||||
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear out all children from the list
|
||||
*/
|
||||
void resetList() {
|
||||
mDataChanged = false;
|
||||
mNeedSync = false;
|
||||
|
||||
removeAllViewsInLayout();
|
||||
mOldSelectedPosition = INVALID_POSITION;
|
||||
mOldSelectedRowId = INVALID_ROW_ID;
|
||||
|
||||
setSelectedPositionInt(INVALID_POSITION);
|
||||
setNextSelectedPositionInt(INVALID_POSITION);
|
||||
invalidate();
|
||||
}
|
||||
|
||||
/**
|
||||
* @see android.view.View#measure(int, int)
|
||||
*
|
||||
* Figure out the dimensions of this Spinner. The width comes from
|
||||
* the widthMeasureSpec as Spinnners can't have their width set to
|
||||
* UNSPECIFIED. The height is based on the height of the selected item
|
||||
* plus padding.
|
||||
*/
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
|
||||
int widthSize;
|
||||
int heightSize;
|
||||
|
||||
final int mPaddingLeft = getPaddingLeft();
|
||||
final int mPaddingTop = getPaddingTop();
|
||||
final int mPaddingRight = getPaddingRight();
|
||||
final int mPaddingBottom = getPaddingBottom();
|
||||
|
||||
mSpinnerPadding.left = mPaddingLeft > mSelectionLeftPadding ? mPaddingLeft
|
||||
: mSelectionLeftPadding;
|
||||
mSpinnerPadding.top = mPaddingTop > mSelectionTopPadding ? mPaddingTop
|
||||
: mSelectionTopPadding;
|
||||
mSpinnerPadding.right = mPaddingRight > mSelectionRightPadding ? mPaddingRight
|
||||
: mSelectionRightPadding;
|
||||
mSpinnerPadding.bottom = mPaddingBottom > mSelectionBottomPadding ? mPaddingBottom
|
||||
: mSelectionBottomPadding;
|
||||
|
||||
if (mDataChanged) {
|
||||
handleDataChanged();
|
||||
}
|
||||
|
||||
int preferredHeight = 0;
|
||||
int preferredWidth = 0;
|
||||
boolean needsMeasuring = true;
|
||||
|
||||
int selectedPosition = getSelectedItemPosition();
|
||||
if (selectedPosition >= 0 && mAdapter != null && selectedPosition < mAdapter.getCount()) {
|
||||
// Try looking in the recycler. (Maybe we were measured once already)
|
||||
View view = mRecycler.get(selectedPosition);
|
||||
if (view == null) {
|
||||
// Make a new one
|
||||
view = mAdapter.getView(selectedPosition, null, this);
|
||||
}
|
||||
|
||||
if (view != null) {
|
||||
// Put in recycler for re-measuring and/or layout
|
||||
mRecycler.put(selectedPosition, view);
|
||||
}
|
||||
|
||||
if (view != null) {
|
||||
if (view.getLayoutParams() == null) {
|
||||
mBlockLayoutRequests = true;
|
||||
view.setLayoutParams(generateDefaultLayoutParams());
|
||||
mBlockLayoutRequests = false;
|
||||
}
|
||||
measureChild(view, widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
preferredHeight = getChildHeight(view) + mSpinnerPadding.top + mSpinnerPadding.bottom;
|
||||
preferredWidth = getChildWidth(view) + mSpinnerPadding.left + mSpinnerPadding.right;
|
||||
|
||||
needsMeasuring = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (needsMeasuring) {
|
||||
// No views -- just use padding
|
||||
preferredHeight = mSpinnerPadding.top + mSpinnerPadding.bottom;
|
||||
if (widthMode == MeasureSpec.UNSPECIFIED) {
|
||||
preferredWidth = mSpinnerPadding.left + mSpinnerPadding.right;
|
||||
}
|
||||
}
|
||||
|
||||
preferredHeight = Math.max(preferredHeight, getSuggestedMinimumHeight());
|
||||
preferredWidth = Math.max(preferredWidth, getSuggestedMinimumWidth());
|
||||
|
||||
if (IS_HONEYCOMB) {
|
||||
heightSize = resolveSizeAndState(preferredHeight, heightMeasureSpec, 0);
|
||||
widthSize = resolveSizeAndState(preferredWidth, widthMeasureSpec, 0);
|
||||
} else {
|
||||
heightSize = resolveSize(preferredHeight, heightMeasureSpec);
|
||||
widthSize = resolveSize(preferredWidth, widthMeasureSpec);
|
||||
}
|
||||
|
||||
setMeasuredDimension(widthSize, heightSize);
|
||||
mHeightMeasureSpec = heightMeasureSpec;
|
||||
mWidthMeasureSpec = widthMeasureSpec;
|
||||
}
|
||||
|
||||
int getChildHeight(View child) {
|
||||
return child.getMeasuredHeight();
|
||||
}
|
||||
|
||||
int getChildWidth(View child) {
|
||||
return child.getMeasuredWidth();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
|
||||
return new ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
}
|
||||
|
||||
void recycleAllViews() {
|
||||
final int childCount = getChildCount();
|
||||
final IcsAbsSpinner.RecycleBin recycleBin = mRecycler;
|
||||
final int position = mFirstPosition;
|
||||
|
||||
// All views go in recycler
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
View v = getChildAt(i);
|
||||
int index = position + i;
|
||||
recycleBin.put(index, v);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Jump directly to a specific item in the adapter data.
|
||||
*/
|
||||
public void setSelection(int position, boolean animate) {
|
||||
// Animate only if requested position is already on screen somewhere
|
||||
boolean shouldAnimate = animate && mFirstPosition <= position &&
|
||||
position <= mFirstPosition + getChildCount() - 1;
|
||||
setSelectionInt(position, shouldAnimate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setSelection(int position) {
|
||||
setNextSelectedPositionInt(position);
|
||||
requestLayout();
|
||||
invalidate();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Makes the item at the supplied position selected.
|
||||
*
|
||||
* @param position Position to select
|
||||
* @param animate Should the transition be animated
|
||||
*
|
||||
*/
|
||||
void setSelectionInt(int position, boolean animate) {
|
||||
if (position != mOldSelectedPosition) {
|
||||
mBlockLayoutRequests = true;
|
||||
int delta = position - mSelectedPosition;
|
||||
setNextSelectedPositionInt(position);
|
||||
layout(delta, animate);
|
||||
mBlockLayoutRequests = false;
|
||||
}
|
||||
}
|
||||
|
||||
abstract void layout(int delta, boolean animate);
|
||||
|
||||
@Override
|
||||
public View getSelectedView() {
|
||||
if (mItemCount > 0 && mSelectedPosition >= 0) {
|
||||
return getChildAt(mSelectedPosition - mFirstPosition);
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Override to prevent spamming ourselves with layout requests
|
||||
* as we place views
|
||||
*
|
||||
* @see android.view.View#requestLayout()
|
||||
*/
|
||||
@Override
|
||||
public void requestLayout() {
|
||||
if (!mBlockLayoutRequests) {
|
||||
super.requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public SpinnerAdapter getAdapter() {
|
||||
return mAdapter;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mItemCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a point to a position in the list.
|
||||
*
|
||||
* @param x X in local coordinate
|
||||
* @param y Y in local coordinate
|
||||
* @return The position of the item which contains the specified point, or
|
||||
* {@link #INVALID_POSITION} if the point does not intersect an item.
|
||||
*/
|
||||
public int pointToPosition(int x, int y) {
|
||||
Rect frame = mTouchFrame;
|
||||
if (frame == null) {
|
||||
mTouchFrame = new Rect();
|
||||
frame = mTouchFrame;
|
||||
}
|
||||
|
||||
final int count = getChildCount();
|
||||
for (int i = count - 1; i >= 0; i--) {
|
||||
View child = getChildAt(i);
|
||||
if (child.getVisibility() == View.VISIBLE) {
|
||||
child.getHitRect(frame);
|
||||
if (frame.contains(x, y)) {
|
||||
return mFirstPosition + i;
|
||||
}
|
||||
}
|
||||
}
|
||||
return INVALID_POSITION;
|
||||
}
|
||||
|
||||
static class SavedState extends BaseSavedState {
|
||||
long selectedId;
|
||||
int position;
|
||||
|
||||
/**
|
||||
* Constructor called from {@link AbsSpinner#onSaveInstanceState()}
|
||||
*/
|
||||
SavedState(Parcelable superState) {
|
||||
super(superState);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor called from {@link #CREATOR}
|
||||
*/
|
||||
private SavedState(Parcel in) {
|
||||
super(in);
|
||||
selectedId = in.readLong();
|
||||
position = in.readInt();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(Parcel out, int flags) {
|
||||
super.writeToParcel(out, flags);
|
||||
out.writeLong(selectedId);
|
||||
out.writeInt(position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "AbsSpinner.SavedState{"
|
||||
+ Integer.toHexString(System.identityHashCode(this))
|
||||
+ " selectedId=" + selectedId
|
||||
+ " position=" + position + "}";
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<SavedState> CREATOR
|
||||
= new Parcelable.Creator<SavedState>() {
|
||||
public SavedState createFromParcel(Parcel in) {
|
||||
return new SavedState(in);
|
||||
}
|
||||
|
||||
public SavedState[] newArray(int size) {
|
||||
return new SavedState[size];
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
public Parcelable onSaveInstanceState() {
|
||||
Parcelable superState = super.onSaveInstanceState();
|
||||
SavedState ss = new SavedState(superState);
|
||||
ss.selectedId = getSelectedItemId();
|
||||
if (ss.selectedId >= 0) {
|
||||
ss.position = getSelectedItemPosition();
|
||||
} else {
|
||||
ss.position = INVALID_POSITION;
|
||||
}
|
||||
return ss;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onRestoreInstanceState(Parcelable state) {
|
||||
SavedState ss = (SavedState) state;
|
||||
|
||||
super.onRestoreInstanceState(ss.getSuperState());
|
||||
|
||||
if (ss.selectedId >= 0) {
|
||||
mDataChanged = true;
|
||||
mNeedSync = true;
|
||||
mSyncRowId = ss.selectedId;
|
||||
mSyncPosition = ss.position;
|
||||
mSyncMode = SYNC_SELECTED_POSITION;
|
||||
requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
class RecycleBin {
|
||||
private final SparseArray<View> mScrapHeap = new SparseArray<View>();
|
||||
|
||||
public void put(int position, View v) {
|
||||
mScrapHeap.put(position, v);
|
||||
}
|
||||
|
||||
View get(int position) {
|
||||
// System.out.print("Looking for " + position);
|
||||
View result = mScrapHeap.get(position);
|
||||
if (result != null) {
|
||||
// System.out.println(" HIT");
|
||||
mScrapHeap.delete(position);
|
||||
} else {
|
||||
// System.out.println(" MISS");
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
void clear() {
|
||||
final SparseArray<View> scrapHeap = mScrapHeap;
|
||||
final int count = scrapHeap.size();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View view = scrapHeap.valueAt(i);
|
||||
if (view != null) {
|
||||
removeDetachedView(view, true);
|
||||
}
|
||||
}
|
||||
scrapHeap.clear();
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,51 +0,0 @@
|
|||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.ColorFilter;
|
||||
import android.graphics.Paint;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
|
||||
/**
|
||||
* A version of {@link android.graphics.drawable.ColorDrawable} that respects bounds.
|
||||
*/
|
||||
public class IcsColorDrawable extends Drawable {
|
||||
private int color;
|
||||
private final Paint paint = new Paint();
|
||||
|
||||
public IcsColorDrawable(ColorDrawable drawable) {
|
||||
Bitmap bitmap = Bitmap.createBitmap(1, 1, Bitmap.Config.ARGB_8888);
|
||||
Canvas c = new Canvas(bitmap);
|
||||
drawable.draw(c);
|
||||
this.color = bitmap.getPixel(0, 0);
|
||||
bitmap.recycle();
|
||||
}
|
||||
|
||||
public IcsColorDrawable(int color) {
|
||||
this.color = color;
|
||||
}
|
||||
|
||||
@Override public void draw(Canvas canvas) {
|
||||
if ((color >>> 24) != 0) {
|
||||
paint.setColor(color);
|
||||
canvas.drawRect(getBounds(), paint);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAlpha(int alpha) {
|
||||
if (alpha != (color >>> 24)) {
|
||||
color = (color & 0x00FFFFFF) | (alpha << 24);
|
||||
invalidateSelf();
|
||||
}
|
||||
}
|
||||
|
||||
@Override public void setColorFilter(ColorFilter colorFilter) {
|
||||
//Ignored
|
||||
}
|
||||
|
||||
@Override public int getOpacity() {
|
||||
return color >>> 24;
|
||||
}
|
||||
}
|
|
@ -1,280 +0,0 @@
|
|||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.drawable.ColorDrawable;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
|
||||
import com.actionbarsherlock.internal.nineoldandroids.widget.NineLinearLayout;
|
||||
|
||||
/**
|
||||
* A simple extension of a regular linear layout that supports the divider API
|
||||
* of Android 4.0+. The dividers are added adjacent to the children by changing
|
||||
* their layout params. If you need to rely on the margins which fall in the
|
||||
* same orientation as the layout you should wrap the child in a simple
|
||||
* {@link android.widget.FrameLayout} so it can receive the margin.
|
||||
*/
|
||||
public class IcsLinearLayout extends NineLinearLayout {
|
||||
private static final int[] R_styleable_LinearLayout = new int[] {
|
||||
/* 0 */ android.R.attr.divider,
|
||||
/* 2 */ android.R.attr.showDividers,
|
||||
/* 3 */ android.R.attr.dividerPadding,
|
||||
};
|
||||
private static final int LinearLayout_divider = 0;
|
||||
private static final int LinearLayout_showDividers = 1;
|
||||
private static final int LinearLayout_dividerPadding = 2;
|
||||
|
||||
/**
|
||||
* Don't show any dividers.
|
||||
*/
|
||||
public static final int SHOW_DIVIDER_NONE = 0;
|
||||
/**
|
||||
* Show a divider at the beginning of the group.
|
||||
*/
|
||||
public static final int SHOW_DIVIDER_BEGINNING = 1;
|
||||
/**
|
||||
* Show dividers between each item in the group.
|
||||
*/
|
||||
public static final int SHOW_DIVIDER_MIDDLE = 2;
|
||||
/**
|
||||
* Show a divider at the end of the group.
|
||||
*/
|
||||
public static final int SHOW_DIVIDER_END = 4;
|
||||
|
||||
|
||||
private Drawable mDivider;
|
||||
private int mDividerWidth;
|
||||
private int mDividerHeight;
|
||||
private int mShowDividers;
|
||||
private int mDividerPadding;
|
||||
|
||||
public IcsLinearLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, /*com.android.internal.R.styleable.*/R_styleable_LinearLayout);
|
||||
|
||||
setDividerDrawable(a.getDrawable(/*com.android.internal.R.styleable.*/LinearLayout_divider));
|
||||
mShowDividers = a.getInt(/*com.android.internal.R.styleable.*/LinearLayout_showDividers, SHOW_DIVIDER_NONE);
|
||||
mDividerPadding = a.getDimensionPixelSize(/*com.android.internal.R.styleable.*/LinearLayout_dividerPadding, 0);
|
||||
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set how dividers should be shown between items in this layout
|
||||
*
|
||||
* @param showDividers One or more of {@link #SHOW_DIVIDER_BEGINNING},
|
||||
* {@link #SHOW_DIVIDER_MIDDLE}, or {@link #SHOW_DIVIDER_END},
|
||||
* or {@link #SHOW_DIVIDER_NONE} to show no dividers.
|
||||
*/
|
||||
public void setShowDividers(int showDividers) {
|
||||
if (showDividers != mShowDividers) {
|
||||
requestLayout();
|
||||
invalidate(); //XXX This is required if you are toggling a divider off
|
||||
}
|
||||
mShowDividers = showDividers;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return A flag set indicating how dividers should be shown around items.
|
||||
* @see #setShowDividers(int)
|
||||
*/
|
||||
public int getShowDividers() {
|
||||
return mShowDividers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a drawable to be used as a divider between items.
|
||||
* @param divider Drawable that will divide each item.
|
||||
* @see #setShowDividers(int)
|
||||
*/
|
||||
public void setDividerDrawable(Drawable divider) {
|
||||
if (divider == mDivider) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Fix for issue #379
|
||||
if (divider instanceof ColorDrawable && Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
|
||||
divider = new IcsColorDrawable((ColorDrawable) divider);
|
||||
}
|
||||
|
||||
mDivider = divider;
|
||||
if (divider != null) {
|
||||
mDividerWidth = divider.getIntrinsicWidth();
|
||||
mDividerHeight = divider.getIntrinsicHeight();
|
||||
} else {
|
||||
mDividerWidth = 0;
|
||||
mDividerHeight = 0;
|
||||
}
|
||||
setWillNotDraw(divider == null);
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set padding displayed on both ends of dividers.
|
||||
*
|
||||
* @param padding Padding value in pixels that will be applied to each end
|
||||
*
|
||||
* @see #setShowDividers(int)
|
||||
* @see #setDividerDrawable(Drawable)
|
||||
* @see #getDividerPadding()
|
||||
*/
|
||||
public void setDividerPadding(int padding) {
|
||||
mDividerPadding = padding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the padding size used to inset dividers in pixels
|
||||
*
|
||||
* @see #setShowDividers(int)
|
||||
* @see #setDividerDrawable(Drawable)
|
||||
* @see #setDividerPadding(int)
|
||||
*/
|
||||
public int getDividerPadding() {
|
||||
return mDividerPadding;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the width of the current divider drawable.
|
||||
*
|
||||
* @hide Used internally by framework.
|
||||
*/
|
||||
public int getDividerWidth() {
|
||||
return mDividerWidth;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void measureChildWithMargins(View child, int parentWidthMeasureSpec, int widthUsed, int parentHeightMeasureSpec, int heightUsed) {
|
||||
final int index = indexOfChild(child);
|
||||
final int orientation = getOrientation();
|
||||
final LayoutParams params = (LayoutParams) child.getLayoutParams();
|
||||
if (hasDividerBeforeChildAt(index)) {
|
||||
if (orientation == VERTICAL) {
|
||||
//Account for the divider by pushing everything up
|
||||
params.topMargin = mDividerHeight;
|
||||
} else {
|
||||
//Account for the divider by pushing everything left
|
||||
params.leftMargin = mDividerWidth;
|
||||
}
|
||||
}
|
||||
|
||||
final int count = getChildCount();
|
||||
if (index == count - 1) {
|
||||
if (hasDividerBeforeChildAt(count)) {
|
||||
if (orientation == VERTICAL) {
|
||||
params.bottomMargin = mDividerHeight;
|
||||
} else {
|
||||
params.rightMargin = mDividerWidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
super.measureChildWithMargins(child, parentWidthMeasureSpec, widthUsed, parentHeightMeasureSpec, heightUsed);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDraw(Canvas canvas) {
|
||||
if (mDivider != null) {
|
||||
if (getOrientation() == VERTICAL) {
|
||||
drawDividersVertical(canvas);
|
||||
} else {
|
||||
drawDividersHorizontal(canvas);
|
||||
}
|
||||
}
|
||||
super.onDraw(canvas);
|
||||
}
|
||||
|
||||
void drawDividersVertical(Canvas canvas) {
|
||||
final int count = getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
|
||||
if (child != null && child.getVisibility() != GONE) {
|
||||
if (hasDividerBeforeChildAt(i)) {
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
final int top = child.getTop() - lp.topMargin/* - mDividerHeight*/;
|
||||
drawHorizontalDivider(canvas, top);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasDividerBeforeChildAt(count)) {
|
||||
final View child = getChildAt(count - 1);
|
||||
int bottom = 0;
|
||||
if (child == null) {
|
||||
bottom = getHeight() - getPaddingBottom() - mDividerHeight;
|
||||
} else {
|
||||
//final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
bottom = child.getBottom()/* + lp.bottomMargin*/;
|
||||
}
|
||||
drawHorizontalDivider(canvas, bottom);
|
||||
}
|
||||
}
|
||||
|
||||
void drawDividersHorizontal(Canvas canvas) {
|
||||
final int count = getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
final View child = getChildAt(i);
|
||||
|
||||
if (child != null && child.getVisibility() != GONE) {
|
||||
if (hasDividerBeforeChildAt(i)) {
|
||||
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
final int left = child.getLeft() - lp.leftMargin/* - mDividerWidth*/;
|
||||
drawVerticalDivider(canvas, left);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (hasDividerBeforeChildAt(count)) {
|
||||
final View child = getChildAt(count - 1);
|
||||
int right = 0;
|
||||
if (child == null) {
|
||||
right = getWidth() - getPaddingRight() - mDividerWidth;
|
||||
} else {
|
||||
//final LayoutParams lp = (LayoutParams) child.getLayoutParams();
|
||||
right = child.getRight()/* + lp.rightMargin*/;
|
||||
}
|
||||
drawVerticalDivider(canvas, right);
|
||||
}
|
||||
}
|
||||
|
||||
void drawHorizontalDivider(Canvas canvas, int top) {
|
||||
mDivider.setBounds(getPaddingLeft() + mDividerPadding, top,
|
||||
getWidth() - getPaddingRight() - mDividerPadding, top + mDividerHeight);
|
||||
mDivider.draw(canvas);
|
||||
}
|
||||
|
||||
void drawVerticalDivider(Canvas canvas, int left) {
|
||||
mDivider.setBounds(left, getPaddingTop() + mDividerPadding,
|
||||
left + mDividerWidth, getHeight() - getPaddingBottom() - mDividerPadding);
|
||||
mDivider.draw(canvas);
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines where to position dividers between children.
|
||||
*
|
||||
* @param childIndex Index of child to check for preceding divider
|
||||
* @return true if there should be a divider before the child at childIndex
|
||||
* @hide Pending API consideration. Currently only used internally by the system.
|
||||
*/
|
||||
protected boolean hasDividerBeforeChildAt(int childIndex) {
|
||||
if (childIndex == 0) {
|
||||
return (mShowDividers & SHOW_DIVIDER_BEGINNING) != 0;
|
||||
} else if (childIndex == getChildCount()) {
|
||||
return (mShowDividers & SHOW_DIVIDER_END) != 0;
|
||||
} else if ((mShowDividers & SHOW_DIVIDER_MIDDLE) != 0) {
|
||||
boolean hasVisibleViewBefore = false;
|
||||
for (int i = childIndex - 1; i >= 0; i--) {
|
||||
if (getChildAt(i).getVisibility() != GONE) {
|
||||
hasVisibleViewBefore = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return hasVisibleViewBefore;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
|
@ -1,661 +0,0 @@
|
|||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import com.actionbarsherlock.R;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Resources;
|
||||
import android.database.DataSetObserver;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.os.Build;
|
||||
import android.os.Handler;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.ContextThemeWrapper;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.View.MeasureSpec;
|
||||
import android.view.View.OnTouchListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
import android.widget.AbsListView;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.PopupWindow;
|
||||
|
||||
/**
|
||||
* A proxy between pre- and post-Honeycomb implementations of this class.
|
||||
*/
|
||||
public class IcsListPopupWindow {
|
||||
/**
|
||||
* This value controls the length of time that the user
|
||||
* must leave a pointer down without scrolling to expand
|
||||
* the autocomplete dropdown list to cover the IME.
|
||||
*/
|
||||
private static final int EXPAND_LIST_TIMEOUT = 250;
|
||||
|
||||
private Context mContext;
|
||||
private PopupWindow mPopup;
|
||||
private ListAdapter mAdapter;
|
||||
private DropDownListView mDropDownList;
|
||||
|
||||
private int mDropDownHeight = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
private int mDropDownWidth = ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
private int mDropDownHorizontalOffset;
|
||||
private int mDropDownVerticalOffset;
|
||||
private boolean mDropDownVerticalOffsetSet;
|
||||
|
||||
private int mListItemExpandMaximum = Integer.MAX_VALUE;
|
||||
|
||||
private View mPromptView;
|
||||
private int mPromptPosition = POSITION_PROMPT_ABOVE;
|
||||
|
||||
private DataSetObserver mObserver;
|
||||
|
||||
private View mDropDownAnchorView;
|
||||
|
||||
private Drawable mDropDownListHighlight;
|
||||
|
||||
private AdapterView.OnItemClickListener mItemClickListener;
|
||||
private AdapterView.OnItemSelectedListener mItemSelectedListener;
|
||||
|
||||
private final ResizePopupRunnable mResizePopupRunnable = new ResizePopupRunnable();
|
||||
private final PopupTouchInterceptor mTouchInterceptor = new PopupTouchInterceptor();
|
||||
private final PopupScrollListener mScrollListener = new PopupScrollListener();
|
||||
private final ListSelectorHider mHideSelector = new ListSelectorHider();
|
||||
|
||||
private Handler mHandler = new Handler();
|
||||
|
||||
private Rect mTempRect = new Rect();
|
||||
|
||||
private boolean mModal;
|
||||
|
||||
public static final int POSITION_PROMPT_ABOVE = 0;
|
||||
public static final int POSITION_PROMPT_BELOW = 1;
|
||||
|
||||
public IcsListPopupWindow(Context context) {
|
||||
this(context, null, R.attr.listPopupWindowStyle);
|
||||
}
|
||||
|
||||
public IcsListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr) {
|
||||
mContext = context;
|
||||
mPopup = new PopupWindow(context, attrs, defStyleAttr);
|
||||
mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
|
||||
}
|
||||
|
||||
public IcsListPopupWindow(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
|
||||
mContext = context;
|
||||
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB) {
|
||||
Context wrapped = new ContextThemeWrapper(context, defStyleRes);
|
||||
mPopup = new PopupWindow(wrapped, attrs, defStyleAttr);
|
||||
} else {
|
||||
mPopup = new PopupWindow(context, attrs, defStyleAttr, defStyleRes);
|
||||
}
|
||||
mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NEEDED);
|
||||
}
|
||||
|
||||
public void setAdapter(ListAdapter adapter) {
|
||||
if (mObserver == null) {
|
||||
mObserver = new PopupDataSetObserver();
|
||||
} else if (mAdapter != null) {
|
||||
mAdapter.unregisterDataSetObserver(mObserver);
|
||||
}
|
||||
mAdapter = adapter;
|
||||
if (mAdapter != null) {
|
||||
adapter.registerDataSetObserver(mObserver);
|
||||
}
|
||||
|
||||
if (mDropDownList != null) {
|
||||
mDropDownList.setAdapter(mAdapter);
|
||||
}
|
||||
}
|
||||
|
||||
public void setPromptPosition(int position) {
|
||||
mPromptPosition = position;
|
||||
}
|
||||
|
||||
public void setModal(boolean modal) {
|
||||
mModal = true;
|
||||
mPopup.setFocusable(modal);
|
||||
}
|
||||
|
||||
public void setBackgroundDrawable(Drawable d) {
|
||||
mPopup.setBackgroundDrawable(d);
|
||||
}
|
||||
|
||||
public void setAnchorView(View anchor) {
|
||||
mDropDownAnchorView = anchor;
|
||||
}
|
||||
|
||||
public void setHorizontalOffset(int offset) {
|
||||
mDropDownHorizontalOffset = offset;
|
||||
}
|
||||
|
||||
public void setVerticalOffset(int offset) {
|
||||
mDropDownVerticalOffset = offset;
|
||||
mDropDownVerticalOffsetSet = true;
|
||||
}
|
||||
|
||||
public void setContentWidth(int width) {
|
||||
Drawable popupBackground = mPopup.getBackground();
|
||||
if (popupBackground != null) {
|
||||
popupBackground.getPadding(mTempRect);
|
||||
mDropDownWidth = mTempRect.left + mTempRect.right + width;
|
||||
} else {
|
||||
mDropDownWidth = width;
|
||||
}
|
||||
}
|
||||
|
||||
public void setOnItemClickListener(AdapterView.OnItemClickListener clickListener) {
|
||||
mItemClickListener = clickListener;
|
||||
}
|
||||
|
||||
public void show() {
|
||||
int height = buildDropDown();
|
||||
|
||||
int widthSpec = 0;
|
||||
int heightSpec = 0;
|
||||
|
||||
boolean noInputMethod = isInputMethodNotNeeded();
|
||||
//XXX mPopup.setAllowScrollingAnchorParent(!noInputMethod);
|
||||
|
||||
if (mPopup.isShowing()) {
|
||||
if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) {
|
||||
// The call to PopupWindow's update method below can accept -1 for any
|
||||
// value you do not want to update.
|
||||
widthSpec = -1;
|
||||
} else if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) {
|
||||
widthSpec = mDropDownAnchorView.getWidth();
|
||||
} else {
|
||||
widthSpec = mDropDownWidth;
|
||||
}
|
||||
|
||||
if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
|
||||
// The call to PopupWindow's update method below can accept -1 for any
|
||||
// value you do not want to update.
|
||||
heightSpec = noInputMethod ? height : ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
if (noInputMethod) {
|
||||
mPopup.setWindowLayoutMode(
|
||||
mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
|
||||
ViewGroup.LayoutParams.MATCH_PARENT : 0, 0);
|
||||
} else {
|
||||
mPopup.setWindowLayoutMode(
|
||||
mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT ?
|
||||
ViewGroup.LayoutParams.MATCH_PARENT : 0,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT);
|
||||
}
|
||||
} else if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
|
||||
heightSpec = height;
|
||||
} else {
|
||||
heightSpec = mDropDownHeight;
|
||||
}
|
||||
|
||||
mPopup.setOutsideTouchable(true);
|
||||
|
||||
mPopup.update(mDropDownAnchorView, mDropDownHorizontalOffset,
|
||||
mDropDownVerticalOffset, widthSpec, heightSpec);
|
||||
} else {
|
||||
if (mDropDownWidth == ViewGroup.LayoutParams.MATCH_PARENT) {
|
||||
widthSpec = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
} else {
|
||||
if (mDropDownWidth == ViewGroup.LayoutParams.WRAP_CONTENT) {
|
||||
mPopup.setWidth(mDropDownAnchorView.getWidth());
|
||||
} else {
|
||||
mPopup.setWidth(mDropDownWidth);
|
||||
}
|
||||
}
|
||||
|
||||
if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
|
||||
heightSpec = ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
} else {
|
||||
if (mDropDownHeight == ViewGroup.LayoutParams.WRAP_CONTENT) {
|
||||
mPopup.setHeight(height);
|
||||
} else {
|
||||
mPopup.setHeight(mDropDownHeight);
|
||||
}
|
||||
}
|
||||
|
||||
mPopup.setWindowLayoutMode(widthSpec, heightSpec);
|
||||
//XXX mPopup.setClipToScreenEnabled(true);
|
||||
|
||||
// use outside touchable to dismiss drop down when touching outside of it, so
|
||||
// only set this if the dropdown is not always visible
|
||||
mPopup.setOutsideTouchable(true);
|
||||
mPopup.setTouchInterceptor(mTouchInterceptor);
|
||||
mPopup.showAsDropDown(mDropDownAnchorView,
|
||||
mDropDownHorizontalOffset, mDropDownVerticalOffset);
|
||||
mDropDownList.setSelection(ListView.INVALID_POSITION);
|
||||
|
||||
if (!mModal || mDropDownList.isInTouchMode()) {
|
||||
clearListSelection();
|
||||
}
|
||||
if (!mModal) {
|
||||
mHandler.post(mHideSelector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void dismiss() {
|
||||
mPopup.dismiss();
|
||||
if (mPromptView != null) {
|
||||
final ViewParent parent = mPromptView.getParent();
|
||||
if (parent instanceof ViewGroup) {
|
||||
final ViewGroup group = (ViewGroup) parent;
|
||||
group.removeView(mPromptView);
|
||||
}
|
||||
}
|
||||
mPopup.setContentView(null);
|
||||
mDropDownList = null;
|
||||
mHandler.removeCallbacks(mResizePopupRunnable);
|
||||
}
|
||||
|
||||
public void setOnDismissListener(PopupWindow.OnDismissListener listener) {
|
||||
mPopup.setOnDismissListener(listener);
|
||||
}
|
||||
|
||||
public void setInputMethodMode(int mode) {
|
||||
mPopup.setInputMethodMode(mode);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the selected position of the list.
|
||||
* Only valid when {@link #isShowing()} == {@code true}.
|
||||
*
|
||||
* @param position List position to set as selected.
|
||||
*/
|
||||
public void setSelection(int position) {
|
||||
DropDownListView list = mDropDownList;
|
||||
if (isShowing() && list != null) {
|
||||
list.mListSelectionHidden = false;
|
||||
list.setSelection(position);
|
||||
if (list.getChoiceMode() != ListView.CHOICE_MODE_NONE) {
|
||||
list.setItemChecked(position, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void clearListSelection() {
|
||||
final DropDownListView list = mDropDownList;
|
||||
if (list != null) {
|
||||
// WARNING: Please read the comment where mListSelectionHidden is declared
|
||||
list.mListSelectionHidden = true;
|
||||
//XXX list.hideSelector();
|
||||
list.requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isShowing() {
|
||||
return mPopup.isShowing();
|
||||
}
|
||||
|
||||
private boolean isInputMethodNotNeeded() {
|
||||
return mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
|
||||
}
|
||||
|
||||
public ListView getListView() {
|
||||
return mDropDownList;
|
||||
}
|
||||
|
||||
private int buildDropDown() {
|
||||
ViewGroup dropDownView;
|
||||
int otherHeights = 0;
|
||||
|
||||
if (mDropDownList == null) {
|
||||
Context context = mContext;
|
||||
|
||||
mDropDownList = new DropDownListView(context, !mModal);
|
||||
if (mDropDownListHighlight != null) {
|
||||
mDropDownList.setSelector(mDropDownListHighlight);
|
||||
}
|
||||
mDropDownList.setAdapter(mAdapter);
|
||||
mDropDownList.setOnItemClickListener(mItemClickListener);
|
||||
mDropDownList.setFocusable(true);
|
||||
mDropDownList.setFocusableInTouchMode(true);
|
||||
mDropDownList.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||
public void onItemSelected(AdapterView<?> parent, View view,
|
||||
int position, long id) {
|
||||
|
||||
if (position != -1) {
|
||||
DropDownListView dropDownList = mDropDownList;
|
||||
|
||||
if (dropDownList != null) {
|
||||
dropDownList.mListSelectionHidden = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
}
|
||||
});
|
||||
mDropDownList.setOnScrollListener(mScrollListener);
|
||||
|
||||
if (mItemSelectedListener != null) {
|
||||
mDropDownList.setOnItemSelectedListener(mItemSelectedListener);
|
||||
}
|
||||
|
||||
dropDownView = mDropDownList;
|
||||
|
||||
View hintView = mPromptView;
|
||||
if (hintView != null) {
|
||||
// if an hint has been specified, we accomodate more space for it and
|
||||
// add a text view in the drop down menu, at the bottom of the list
|
||||
LinearLayout hintContainer = new LinearLayout(context);
|
||||
hintContainer.setOrientation(LinearLayout.VERTICAL);
|
||||
|
||||
LinearLayout.LayoutParams hintParams = new LinearLayout.LayoutParams(
|
||||
ViewGroup.LayoutParams.MATCH_PARENT, 0, 1.0f
|
||||
);
|
||||
|
||||
switch (mPromptPosition) {
|
||||
case POSITION_PROMPT_BELOW:
|
||||
hintContainer.addView(dropDownView, hintParams);
|
||||
hintContainer.addView(hintView);
|
||||
break;
|
||||
|
||||
case POSITION_PROMPT_ABOVE:
|
||||
hintContainer.addView(hintView);
|
||||
hintContainer.addView(dropDownView, hintParams);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// measure the hint's height to find how much more vertical space
|
||||
// we need to add to the drop down's height
|
||||
int widthSpec = MeasureSpec.makeMeasureSpec(mDropDownWidth, MeasureSpec.AT_MOST);
|
||||
int heightSpec = MeasureSpec.UNSPECIFIED;
|
||||
hintView.measure(widthSpec, heightSpec);
|
||||
|
||||
hintParams = (LinearLayout.LayoutParams) hintView.getLayoutParams();
|
||||
otherHeights = hintView.getMeasuredHeight() + hintParams.topMargin
|
||||
+ hintParams.bottomMargin;
|
||||
|
||||
dropDownView = hintContainer;
|
||||
}
|
||||
|
||||
mPopup.setContentView(dropDownView);
|
||||
} else {
|
||||
dropDownView = (ViewGroup) mPopup.getContentView();
|
||||
final View view = mPromptView;
|
||||
if (view != null) {
|
||||
LinearLayout.LayoutParams hintParams =
|
||||
(LinearLayout.LayoutParams) view.getLayoutParams();
|
||||
otherHeights = view.getMeasuredHeight() + hintParams.topMargin
|
||||
+ hintParams.bottomMargin;
|
||||
}
|
||||
}
|
||||
|
||||
// getMaxAvailableHeight() subtracts the padding, so we put it back
|
||||
// to get the available height for the whole window
|
||||
int padding = 0;
|
||||
Drawable background = mPopup.getBackground();
|
||||
if (background != null) {
|
||||
background.getPadding(mTempRect);
|
||||
padding = mTempRect.top + mTempRect.bottom;
|
||||
|
||||
// If we don't have an explicit vertical offset, determine one from the window
|
||||
// background so that content will line up.
|
||||
if (!mDropDownVerticalOffsetSet) {
|
||||
mDropDownVerticalOffset = -mTempRect.top;
|
||||
}
|
||||
}
|
||||
|
||||
// Max height available on the screen for a popup.
|
||||
boolean ignoreBottomDecorations =
|
||||
mPopup.getInputMethodMode() == PopupWindow.INPUT_METHOD_NOT_NEEDED;
|
||||
final int maxHeight = /*mPopup.*/getMaxAvailableHeight(
|
||||
mDropDownAnchorView, mDropDownVerticalOffset, ignoreBottomDecorations);
|
||||
|
||||
if (mDropDownHeight == ViewGroup.LayoutParams.MATCH_PARENT) {
|
||||
return maxHeight + padding;
|
||||
}
|
||||
|
||||
final int listContent = /*mDropDownList.*/measureHeightOfChildren(MeasureSpec.UNSPECIFIED,
|
||||
0, -1/*ListView.NO_POSITION*/, maxHeight - otherHeights, -1);
|
||||
// add padding only if the list has items in it, that way we don't show
|
||||
// the popup if it is not needed
|
||||
if (listContent > 0) otherHeights += padding;
|
||||
|
||||
return listContent + otherHeights;
|
||||
}
|
||||
|
||||
private int getMaxAvailableHeight(View anchor, int yOffset, boolean ignoreBottomDecorations) {
|
||||
final Rect displayFrame = new Rect();
|
||||
anchor.getWindowVisibleDisplayFrame(displayFrame);
|
||||
|
||||
final int[] anchorPos = new int[2];
|
||||
anchor.getLocationOnScreen(anchorPos);
|
||||
|
||||
int bottomEdge = displayFrame.bottom;
|
||||
if (ignoreBottomDecorations) {
|
||||
Resources res = anchor.getContext().getResources();
|
||||
bottomEdge = res.getDisplayMetrics().heightPixels;
|
||||
}
|
||||
final int distanceToBottom = bottomEdge - (anchorPos[1] + anchor.getHeight()) - yOffset;
|
||||
final int distanceToTop = anchorPos[1] - displayFrame.top + yOffset;
|
||||
|
||||
// anchorPos[1] is distance from anchor to top of screen
|
||||
int returnedHeight = Math.max(distanceToBottom, distanceToTop);
|
||||
if (mPopup.getBackground() != null) {
|
||||
mPopup.getBackground().getPadding(mTempRect);
|
||||
returnedHeight -= mTempRect.top + mTempRect.bottom;
|
||||
}
|
||||
|
||||
return returnedHeight;
|
||||
}
|
||||
|
||||
private int measureHeightOfChildren(int widthMeasureSpec, int startPosition, int endPosition,
|
||||
final int maxHeight, int disallowPartialChildPosition) {
|
||||
|
||||
final ListAdapter adapter = mAdapter;
|
||||
if (adapter == null) {
|
||||
return mDropDownList.getListPaddingTop() + mDropDownList.getListPaddingBottom();
|
||||
}
|
||||
|
||||
// Include the padding of the list
|
||||
int returnedHeight = mDropDownList.getListPaddingTop() + mDropDownList.getListPaddingBottom();
|
||||
final int dividerHeight = ((mDropDownList.getDividerHeight() > 0) && mDropDownList.getDivider() != null) ? mDropDownList.getDividerHeight() : 0;
|
||||
// The previous height value that was less than maxHeight and contained
|
||||
// no partial children
|
||||
int prevHeightWithoutPartialChild = 0;
|
||||
int i;
|
||||
View child;
|
||||
|
||||
// mItemCount - 1 since endPosition parameter is inclusive
|
||||
endPosition = (endPosition == -1/*NO_POSITION*/) ? adapter.getCount() - 1 : endPosition;
|
||||
|
||||
for (i = startPosition; i <= endPosition; ++i) {
|
||||
child = mAdapter.getView(i, null, mDropDownList);
|
||||
if (mDropDownList.getCacheColorHint() != 0) {
|
||||
child.setDrawingCacheBackgroundColor(mDropDownList.getCacheColorHint());
|
||||
}
|
||||
|
||||
measureScrapChild(child, i, widthMeasureSpec);
|
||||
|
||||
if (i > 0) {
|
||||
// Count the divider for all but one child
|
||||
returnedHeight += dividerHeight;
|
||||
}
|
||||
|
||||
returnedHeight += child.getMeasuredHeight();
|
||||
|
||||
if (returnedHeight >= maxHeight) {
|
||||
// We went over, figure out which height to return. If returnedHeight > maxHeight,
|
||||
// then the i'th position did not fit completely.
|
||||
return (disallowPartialChildPosition >= 0) // Disallowing is enabled (> -1)
|
||||
&& (i > disallowPartialChildPosition) // We've past the min pos
|
||||
&& (prevHeightWithoutPartialChild > 0) // We have a prev height
|
||||
&& (returnedHeight != maxHeight) // i'th child did not fit completely
|
||||
? prevHeightWithoutPartialChild
|
||||
: maxHeight;
|
||||
}
|
||||
|
||||
if ((disallowPartialChildPosition >= 0) && (i >= disallowPartialChildPosition)) {
|
||||
prevHeightWithoutPartialChild = returnedHeight;
|
||||
}
|
||||
}
|
||||
|
||||
// At this point, we went through the range of children, and they each
|
||||
// completely fit, so return the returnedHeight
|
||||
return returnedHeight;
|
||||
}
|
||||
private void measureScrapChild(View child, int position, int widthMeasureSpec) {
|
||||
ListView.LayoutParams p = (ListView.LayoutParams) child.getLayoutParams();
|
||||
if (p == null) {
|
||||
p = new ListView.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT, 0);
|
||||
child.setLayoutParams(p);
|
||||
}
|
||||
//XXX p.viewType = mAdapter.getItemViewType(position);
|
||||
//XXX p.forceAdd = true;
|
||||
|
||||
int childWidthSpec = ViewGroup.getChildMeasureSpec(widthMeasureSpec,
|
||||
mDropDownList.getPaddingLeft() + mDropDownList.getPaddingRight(), p.width);
|
||||
int lpHeight = p.height;
|
||||
int childHeightSpec;
|
||||
if (lpHeight > 0) {
|
||||
childHeightSpec = MeasureSpec.makeMeasureSpec(lpHeight, MeasureSpec.EXACTLY);
|
||||
} else {
|
||||
childHeightSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
}
|
||||
child.measure(childWidthSpec, childHeightSpec);
|
||||
}
|
||||
|
||||
private static class DropDownListView extends ListView {
|
||||
/*
|
||||
* WARNING: This is a workaround for a touch mode issue.
|
||||
*
|
||||
* Touch mode is propagated lazily to windows. This causes problems in
|
||||
* the following scenario:
|
||||
* - Type something in the AutoCompleteTextView and get some results
|
||||
* - Move down with the d-pad to select an item in the list
|
||||
* - Move up with the d-pad until the selection disappears
|
||||
* - Type more text in the AutoCompleteTextView *using the soft keyboard*
|
||||
* and get new results; you are now in touch mode
|
||||
* - The selection comes back on the first item in the list, even though
|
||||
* the list is supposed to be in touch mode
|
||||
*
|
||||
* Using the soft keyboard triggers the touch mode change but that change
|
||||
* is propagated to our window only after the first list layout, therefore
|
||||
* after the list attempts to resurrect the selection.
|
||||
*
|
||||
* The trick to work around this issue is to pretend the list is in touch
|
||||
* mode when we know that the selection should not appear, that is when
|
||||
* we know the user moved the selection away from the list.
|
||||
*
|
||||
* This boolean is set to true whenever we explicitly hide the list's
|
||||
* selection and reset to false whenever we know the user moved the
|
||||
* selection back to the list.
|
||||
*
|
||||
* When this boolean is true, isInTouchMode() returns true, otherwise it
|
||||
* returns super.isInTouchMode().
|
||||
*/
|
||||
private boolean mListSelectionHidden;
|
||||
|
||||
private boolean mHijackFocus;
|
||||
|
||||
public DropDownListView(Context context, boolean hijackFocus) {
|
||||
super(context, null, /*com.android.internal.*/R.attr.dropDownListViewStyle);
|
||||
mHijackFocus = hijackFocus;
|
||||
// TODO: Add an API to control this
|
||||
setCacheColorHint(0); // Transparent, since the background drawable could be anything.
|
||||
}
|
||||
|
||||
//XXX @Override
|
||||
//View obtainView(int position, boolean[] isScrap) {
|
||||
// View view = super.obtainView(position, isScrap);
|
||||
|
||||
// if (view instanceof TextView) {
|
||||
// ((TextView) view).setHorizontallyScrolling(true);
|
||||
// }
|
||||
|
||||
// return view;
|
||||
//}
|
||||
|
||||
@Override
|
||||
public boolean isInTouchMode() {
|
||||
// WARNING: Please read the comment where mListSelectionHidden is declared
|
||||
return (mHijackFocus && mListSelectionHidden) || super.isInTouchMode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasWindowFocus() {
|
||||
return mHijackFocus || super.hasWindowFocus();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFocused() {
|
||||
return mHijackFocus || super.isFocused();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasFocus() {
|
||||
return mHijackFocus || super.hasFocus();
|
||||
}
|
||||
}
|
||||
|
||||
private class PopupDataSetObserver extends DataSetObserver {
|
||||
@Override
|
||||
public void onChanged() {
|
||||
if (isShowing()) {
|
||||
// Resize the popup to fit new content
|
||||
show();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onInvalidated() {
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
private class ListSelectorHider implements Runnable {
|
||||
public void run() {
|
||||
clearListSelection();
|
||||
}
|
||||
}
|
||||
|
||||
private class ResizePopupRunnable implements Runnable {
|
||||
public void run() {
|
||||
if (mDropDownList != null && mDropDownList.getCount() > mDropDownList.getChildCount() &&
|
||||
mDropDownList.getChildCount() <= mListItemExpandMaximum) {
|
||||
mPopup.setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
|
||||
show();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class PopupTouchInterceptor implements OnTouchListener {
|
||||
public boolean onTouch(View v, MotionEvent event) {
|
||||
final int action = event.getAction();
|
||||
final int x = (int) event.getX();
|
||||
final int y = (int) event.getY();
|
||||
|
||||
if (action == MotionEvent.ACTION_DOWN &&
|
||||
mPopup != null && mPopup.isShowing() &&
|
||||
(x >= 0 && x < mPopup.getWidth() && y >= 0 && y < mPopup.getHeight())) {
|
||||
mHandler.postDelayed(mResizePopupRunnable, EXPAND_LIST_TIMEOUT);
|
||||
} else if (action == MotionEvent.ACTION_UP) {
|
||||
mHandler.removeCallbacks(mResizePopupRunnable);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private class PopupScrollListener implements ListView.OnScrollListener {
|
||||
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount,
|
||||
int totalItemCount) {
|
||||
|
||||
}
|
||||
|
||||
public void onScrollStateChanged(AbsListView view, int scrollState) {
|
||||
if (scrollState == SCROLL_STATE_TOUCH_SCROLL &&
|
||||
!isInputMethodNotNeeded() && mPopup.getContentView() != null) {
|
||||
mHandler.removeCallbacks(mResizePopupRunnable);
|
||||
mResizePopupRunnable.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,703 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
|
||||
import static android.view.ViewGroup.LayoutParams.WRAP_CONTENT;
|
||||
import com.actionbarsherlock.R;
|
||||
import android.content.Context;
|
||||
import android.content.DialogInterface;
|
||||
import android.content.DialogInterface.OnClickListener;
|
||||
import android.content.res.TypedArray;
|
||||
import android.database.DataSetObserver;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.AdapterView.OnItemClickListener;
|
||||
import android.widget.ListAdapter;
|
||||
import android.widget.ListView;
|
||||
import android.widget.PopupWindow;
|
||||
import android.widget.SpinnerAdapter;
|
||||
|
||||
|
||||
/**
|
||||
* A view that displays one child at a time and lets the user pick among them.
|
||||
* The items in the Spinner come from the {@link Adapter} associated with
|
||||
* this view.
|
||||
*
|
||||
* <p>See the <a href="{@docRoot}resources/tutorials/views/hello-spinner.html">Spinner
|
||||
* tutorial</a>.</p>
|
||||
*
|
||||
* @attr ref android.R.styleable#Spinner_prompt
|
||||
*/
|
||||
public class IcsSpinner extends IcsAbsSpinner implements OnClickListener {
|
||||
//private static final String TAG = "Spinner";
|
||||
|
||||
// Only measure this many items to get a decent max width.
|
||||
private static final int MAX_ITEMS_MEASURED = 15;
|
||||
|
||||
/**
|
||||
* Use a dialog window for selecting spinner options.
|
||||
*/
|
||||
//public static final int MODE_DIALOG = 0;
|
||||
|
||||
/**
|
||||
* Use a dropdown anchored to the Spinner for selecting spinner options.
|
||||
*/
|
||||
public static final int MODE_DROPDOWN = 1;
|
||||
|
||||
/**
|
||||
* Use the theme-supplied value to select the dropdown mode.
|
||||
*/
|
||||
//private static final int MODE_THEME = -1;
|
||||
|
||||
private SpinnerPopup mPopup;
|
||||
private DropDownAdapter mTempAdapter;
|
||||
int mDropDownWidth;
|
||||
|
||||
private int mGravity;
|
||||
private boolean mDisableChildrenWhenDisabled;
|
||||
|
||||
private Rect mTempRect = new Rect();
|
||||
|
||||
public IcsSpinner(Context context, AttributeSet attrs) {
|
||||
this(context, attrs, R.attr.actionDropDownStyle);
|
||||
}
|
||||
|
||||
/**
|
||||
* Construct a new spinner with the given context's theme, the supplied attribute set,
|
||||
* and default style.
|
||||
*
|
||||
* @param context The Context the view is running in, through which it can
|
||||
* access the current theme, resources, etc.
|
||||
* @param attrs The attributes of the XML tag that is inflating the view.
|
||||
* @param defStyle The default style to apply to this view. If 0, no style
|
||||
* will be applied (beyond what is included in the theme). This may
|
||||
* either be an attribute resource, whose value will be retrieved
|
||||
* from the current theme, or an explicit style resource.
|
||||
*/
|
||||
public IcsSpinner(Context context, AttributeSet attrs, int defStyle) {
|
||||
super(context, attrs, defStyle);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs,
|
||||
R.styleable.SherlockSpinner, defStyle, 0);
|
||||
|
||||
|
||||
DropdownPopup popup = new DropdownPopup(context, attrs, defStyle);
|
||||
|
||||
mDropDownWidth = a.getLayoutDimension(
|
||||
R.styleable.SherlockSpinner_android_dropDownWidth,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT);
|
||||
popup.setBackgroundDrawable(a.getDrawable(
|
||||
R.styleable.SherlockSpinner_android_popupBackground));
|
||||
final int verticalOffset = a.getDimensionPixelOffset(
|
||||
R.styleable.SherlockSpinner_android_dropDownVerticalOffset, 0);
|
||||
if (verticalOffset != 0) {
|
||||
popup.setVerticalOffset(verticalOffset);
|
||||
}
|
||||
|
||||
final int horizontalOffset = a.getDimensionPixelOffset(
|
||||
R.styleable.SherlockSpinner_android_dropDownHorizontalOffset, 0);
|
||||
if (horizontalOffset != 0) {
|
||||
popup.setHorizontalOffset(horizontalOffset);
|
||||
}
|
||||
|
||||
mPopup = popup;
|
||||
|
||||
mGravity = a.getInt(R.styleable.SherlockSpinner_android_gravity, Gravity.CENTER);
|
||||
|
||||
mPopup.setPromptText(a.getString(R.styleable.SherlockSpinner_android_prompt));
|
||||
|
||||
mDisableChildrenWhenDisabled = true;
|
||||
|
||||
a.recycle();
|
||||
|
||||
// Base constructor can call setAdapter before we initialize mPopup.
|
||||
// Finish setting things up if this happened.
|
||||
if (mTempAdapter != null) {
|
||||
mPopup.setAdapter(mTempAdapter);
|
||||
mTempAdapter = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setEnabled(boolean enabled) {
|
||||
super.setEnabled(enabled);
|
||||
if (mDisableChildrenWhenDisabled) {
|
||||
final int count = getChildCount();
|
||||
for (int i = 0; i < count; i++) {
|
||||
getChildAt(i).setEnabled(enabled);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Describes how the selected item view is positioned. Currently only the horizontal component
|
||||
* is used. The default is determined by the current theme.
|
||||
*
|
||||
* @param gravity See {@link android.view.Gravity}
|
||||
*
|
||||
* @attr ref android.R.styleable#Spinner_gravity
|
||||
*/
|
||||
public void setGravity(int gravity) {
|
||||
if (mGravity != gravity) {
|
||||
if ((gravity & Gravity.HORIZONTAL_GRAVITY_MASK) == 0) {
|
||||
gravity |= Gravity.LEFT;
|
||||
}
|
||||
mGravity = gravity;
|
||||
requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAdapter(SpinnerAdapter adapter) {
|
||||
super.setAdapter(adapter);
|
||||
|
||||
if (mPopup != null) {
|
||||
mPopup.setAdapter(new DropDownAdapter(adapter));
|
||||
} else {
|
||||
mTempAdapter = new DropDownAdapter(adapter);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getBaseline() {
|
||||
View child = null;
|
||||
|
||||
if (getChildCount() > 0) {
|
||||
child = getChildAt(0);
|
||||
} else if (mAdapter != null && mAdapter.getCount() > 0) {
|
||||
child = makeAndAddView(0);
|
||||
mRecycler.put(0, child);
|
||||
removeAllViewsInLayout();
|
||||
}
|
||||
|
||||
if (child != null) {
|
||||
final int childBaseline = child.getBaseline();
|
||||
return childBaseline >= 0 ? child.getTop() + childBaseline : -1;
|
||||
} else {
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
|
||||
if (mPopup != null && mPopup.isShowing()) {
|
||||
mPopup.dismiss();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>A spinner does not support item click events. Calling this method
|
||||
* will raise an exception.</p>
|
||||
*
|
||||
* @param l this listener will be ignored
|
||||
*/
|
||||
@Override
|
||||
public void setOnItemClickListener(OnItemClickListener l) {
|
||||
throw new RuntimeException("setOnItemClickListener cannot be used with a spinner.");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
if (mPopup != null && MeasureSpec.getMode(widthMeasureSpec) == MeasureSpec.AT_MOST) {
|
||||
final int measuredWidth = getMeasuredWidth();
|
||||
setMeasuredDimension(Math.min(Math.max(measuredWidth,
|
||||
measureContentWidth(getAdapter(), getBackground())),
|
||||
MeasureSpec.getSize(widthMeasureSpec)),
|
||||
getMeasuredHeight());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @see android.view.View#onLayout(boolean,int,int,int,int)
|
||||
*
|
||||
* Creates and positions all views
|
||||
*
|
||||
*/
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int l, int t, int r, int b) {
|
||||
super.onLayout(changed, l, t, r, b);
|
||||
mInLayout = true;
|
||||
layout(0, false);
|
||||
mInLayout = false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates and positions all views for this Spinner.
|
||||
*
|
||||
* @param delta Change in the selected position. +1 moves selection is moving to the right,
|
||||
* so views are scrolling to the left. -1 means selection is moving to the left.
|
||||
*/
|
||||
@Override
|
||||
void layout(int delta, boolean animate) {
|
||||
int childrenLeft = mSpinnerPadding.left;
|
||||
int childrenWidth = getRight() - getLeft() - mSpinnerPadding.left - mSpinnerPadding.right;
|
||||
|
||||
if (mDataChanged) {
|
||||
handleDataChanged();
|
||||
}
|
||||
|
||||
// Handle the empty set by removing all views
|
||||
if (mItemCount == 0) {
|
||||
resetList();
|
||||
return;
|
||||
}
|
||||
|
||||
if (mNextSelectedPosition >= 0) {
|
||||
setSelectedPositionInt(mNextSelectedPosition);
|
||||
}
|
||||
|
||||
recycleAllViews();
|
||||
|
||||
// Clear out old views
|
||||
removeAllViewsInLayout();
|
||||
|
||||
// Make selected view and position it
|
||||
mFirstPosition = mSelectedPosition;
|
||||
View sel = makeAndAddView(mSelectedPosition);
|
||||
int width = sel.getMeasuredWidth();
|
||||
int selectedOffset = childrenLeft;
|
||||
switch (mGravity & Gravity.HORIZONTAL_GRAVITY_MASK) {
|
||||
case Gravity.CENTER_HORIZONTAL:
|
||||
selectedOffset = childrenLeft + (childrenWidth / 2) - (width / 2);
|
||||
break;
|
||||
case Gravity.RIGHT:
|
||||
selectedOffset = childrenLeft + childrenWidth - width;
|
||||
break;
|
||||
}
|
||||
sel.offsetLeftAndRight(selectedOffset);
|
||||
|
||||
// Flush any cached views that did not get reused above
|
||||
mRecycler.clear();
|
||||
|
||||
invalidate();
|
||||
|
||||
checkSelectionChanged();
|
||||
|
||||
mDataChanged = false;
|
||||
mNeedSync = false;
|
||||
setNextSelectedPositionInt(mSelectedPosition);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obtain a view, either by pulling an existing view from the recycler or
|
||||
* by getting a new one from the adapter. If we are animating, make sure
|
||||
* there is enough information in the view's layout parameters to animate
|
||||
* from the old to new positions.
|
||||
*
|
||||
* @param position Position in the spinner for the view to obtain
|
||||
* @return A view that has been added to the spinner
|
||||
*/
|
||||
private View makeAndAddView(int position) {
|
||||
|
||||
View child;
|
||||
|
||||
if (!mDataChanged) {
|
||||
child = mRecycler.get(position);
|
||||
if (child != null) {
|
||||
// Position the view
|
||||
setUpChild(child);
|
||||
|
||||
return child;
|
||||
}
|
||||
}
|
||||
|
||||
// Nothing found in the recycler -- ask the adapter for a view
|
||||
child = mAdapter.getView(position, null, this);
|
||||
|
||||
// Position the view
|
||||
setUpChild(child);
|
||||
|
||||
return child;
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper for makeAndAddView to set the position of a view
|
||||
* and fill out its layout paramters.
|
||||
*
|
||||
* @param child The view to position
|
||||
*/
|
||||
private void setUpChild(View child) {
|
||||
|
||||
// Respect layout params that are already in the view. Otherwise
|
||||
// make some up...
|
||||
ViewGroup.LayoutParams lp = child.getLayoutParams();
|
||||
if (lp == null) {
|
||||
lp = generateDefaultLayoutParams();
|
||||
}
|
||||
|
||||
addViewInLayout(child, 0, lp);
|
||||
|
||||
child.setSelected(hasFocus());
|
||||
if (mDisableChildrenWhenDisabled) {
|
||||
child.setEnabled(isEnabled());
|
||||
}
|
||||
|
||||
// Get measure specs
|
||||
int childHeightSpec = ViewGroup.getChildMeasureSpec(mHeightMeasureSpec,
|
||||
mSpinnerPadding.top + mSpinnerPadding.bottom, lp.height);
|
||||
int childWidthSpec = ViewGroup.getChildMeasureSpec(mWidthMeasureSpec,
|
||||
mSpinnerPadding.left + mSpinnerPadding.right, lp.width);
|
||||
|
||||
// Measure child
|
||||
child.measure(childWidthSpec, childHeightSpec);
|
||||
|
||||
int childLeft;
|
||||
int childRight;
|
||||
|
||||
// Position vertically based on gravity setting
|
||||
int childTop = mSpinnerPadding.top
|
||||
+ ((getMeasuredHeight() - mSpinnerPadding.bottom -
|
||||
mSpinnerPadding.top - child.getMeasuredHeight()) / 2);
|
||||
int childBottom = childTop + child.getMeasuredHeight();
|
||||
|
||||
int width = child.getMeasuredWidth();
|
||||
childLeft = 0;
|
||||
childRight = childLeft + width;
|
||||
|
||||
child.layout(childLeft, childTop, childRight, childBottom);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean performClick() {
|
||||
boolean handled = super.performClick();
|
||||
|
||||
if (!handled) {
|
||||
handled = true;
|
||||
|
||||
if (!mPopup.isShowing()) {
|
||||
mPopup.show();
|
||||
}
|
||||
}
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
setSelection(which);
|
||||
dialog.dismiss();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the prompt to display when the dialog is shown.
|
||||
* @param prompt the prompt to set
|
||||
*/
|
||||
public void setPrompt(CharSequence prompt) {
|
||||
mPopup.setPromptText(prompt);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the prompt to display when the dialog is shown.
|
||||
* @param promptId the resource ID of the prompt to display when the dialog is shown
|
||||
*/
|
||||
public void setPromptId(int promptId) {
|
||||
setPrompt(getContext().getText(promptId));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return The prompt to display when the dialog is shown
|
||||
*/
|
||||
public CharSequence getPrompt() {
|
||||
return mPopup.getHintText();
|
||||
}
|
||||
|
||||
int measureContentWidth(SpinnerAdapter adapter, Drawable background) {
|
||||
if (adapter == null) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
int width = 0;
|
||||
View itemView = null;
|
||||
int itemType = 0;
|
||||
final int widthMeasureSpec =
|
||||
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
final int heightMeasureSpec =
|
||||
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
|
||||
|
||||
// Make sure the number of items we'll measure is capped. If it's a huge data set
|
||||
// with wildly varying sizes, oh well.
|
||||
int start = Math.max(0, getSelectedItemPosition());
|
||||
final int end = Math.min(adapter.getCount(), start + MAX_ITEMS_MEASURED);
|
||||
final int count = end - start;
|
||||
start = Math.max(0, start - (MAX_ITEMS_MEASURED - count));
|
||||
for (int i = start; i < end; i++) {
|
||||
final int positionType = adapter.getItemViewType(i);
|
||||
if (positionType != itemType) {
|
||||
itemType = positionType;
|
||||
itemView = null;
|
||||
}
|
||||
itemView = adapter.getView(i, itemView, this);
|
||||
if (itemView.getLayoutParams() == null) {
|
||||
itemView.setLayoutParams(new ViewGroup.LayoutParams(
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
}
|
||||
itemView.measure(widthMeasureSpec, heightMeasureSpec);
|
||||
width = Math.max(width, itemView.getMeasuredWidth());
|
||||
}
|
||||
|
||||
// Add background padding to measured width
|
||||
if (background != null) {
|
||||
background.getPadding(mTempRect);
|
||||
width += mTempRect.left + mTempRect.right;
|
||||
}
|
||||
|
||||
return width;
|
||||
}
|
||||
|
||||
/**
|
||||
* <p>Wrapper class for an Adapter. Transforms the embedded Adapter instance
|
||||
* into a ListAdapter.</p>
|
||||
*/
|
||||
private static class DropDownAdapter implements ListAdapter, SpinnerAdapter {
|
||||
private SpinnerAdapter mAdapter;
|
||||
private ListAdapter mListAdapter;
|
||||
|
||||
/**
|
||||
* <p>Creates a new ListAdapter wrapper for the specified adapter.</p>
|
||||
*
|
||||
* @param adapter the Adapter to transform into a ListAdapter
|
||||
*/
|
||||
public DropDownAdapter(SpinnerAdapter adapter) {
|
||||
this.mAdapter = adapter;
|
||||
if (adapter instanceof ListAdapter) {
|
||||
this.mListAdapter = (ListAdapter) adapter;
|
||||
}
|
||||
}
|
||||
|
||||
public int getCount() {
|
||||
return mAdapter == null ? 0 : mAdapter.getCount();
|
||||
}
|
||||
|
||||
public Object getItem(int position) {
|
||||
return mAdapter == null ? null : mAdapter.getItem(position);
|
||||
}
|
||||
|
||||
public long getItemId(int position) {
|
||||
return mAdapter == null ? -1 : mAdapter.getItemId(position);
|
||||
}
|
||||
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
return getDropDownView(position, convertView, parent);
|
||||
}
|
||||
|
||||
public View getDropDownView(int position, View convertView, ViewGroup parent) {
|
||||
return mAdapter == null ? null :
|
||||
mAdapter.getDropDownView(position, convertView, parent);
|
||||
}
|
||||
|
||||
public boolean hasStableIds() {
|
||||
return mAdapter != null && mAdapter.hasStableIds();
|
||||
}
|
||||
|
||||
public void registerDataSetObserver(DataSetObserver observer) {
|
||||
if (mAdapter != null) {
|
||||
mAdapter.registerDataSetObserver(observer);
|
||||
}
|
||||
}
|
||||
|
||||
public void unregisterDataSetObserver(DataSetObserver observer) {
|
||||
if (mAdapter != null) {
|
||||
mAdapter.unregisterDataSetObserver(observer);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the wrapped SpinnerAdapter is also a ListAdapter, delegate this call.
|
||||
* Otherwise, return true.
|
||||
*/
|
||||
public boolean areAllItemsEnabled() {
|
||||
final ListAdapter adapter = mListAdapter;
|
||||
if (adapter != null) {
|
||||
return adapter.areAllItemsEnabled();
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If the wrapped SpinnerAdapter is also a ListAdapter, delegate this call.
|
||||
* Otherwise, return true.
|
||||
*/
|
||||
public boolean isEnabled(int position) {
|
||||
final ListAdapter adapter = mListAdapter;
|
||||
if (adapter != null) {
|
||||
return adapter.isEnabled(position);
|
||||
} else {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public int getItemViewType(int position) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
public int getViewTypeCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
public boolean isEmpty() {
|
||||
return getCount() == 0;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Implements some sort of popup selection interface for selecting a spinner option.
|
||||
* Allows for different spinner modes.
|
||||
*/
|
||||
private interface SpinnerPopup {
|
||||
public void setAdapter(ListAdapter adapter);
|
||||
|
||||
/**
|
||||
* Show the popup
|
||||
*/
|
||||
public void show();
|
||||
|
||||
/**
|
||||
* Dismiss the popup
|
||||
*/
|
||||
public void dismiss();
|
||||
|
||||
/**
|
||||
* @return true if the popup is showing, false otherwise.
|
||||
*/
|
||||
public boolean isShowing();
|
||||
|
||||
/**
|
||||
* Set hint text to be displayed to the user. This should provide
|
||||
* a description of the choice being made.
|
||||
* @param hintText Hint text to set.
|
||||
*/
|
||||
public void setPromptText(CharSequence hintText);
|
||||
public CharSequence getHintText();
|
||||
}
|
||||
|
||||
/*
|
||||
private class DialogPopup implements SpinnerPopup, DialogInterface.OnClickListener {
|
||||
private AlertDialog mPopup;
|
||||
private ListAdapter mListAdapter;
|
||||
private CharSequence mPrompt;
|
||||
|
||||
public void dismiss() {
|
||||
mPopup.dismiss();
|
||||
mPopup = null;
|
||||
}
|
||||
|
||||
public boolean isShowing() {
|
||||
return mPopup != null ? mPopup.isShowing() : false;
|
||||
}
|
||||
|
||||
public void setAdapter(ListAdapter adapter) {
|
||||
mListAdapter = adapter;
|
||||
}
|
||||
|
||||
public void setPromptText(CharSequence hintText) {
|
||||
mPrompt = hintText;
|
||||
}
|
||||
|
||||
public CharSequence getHintText() {
|
||||
return mPrompt;
|
||||
}
|
||||
|
||||
public void show() {
|
||||
AlertDialog.Builder builder = new AlertDialog.Builder(getContext());
|
||||
if (mPrompt != null) {
|
||||
builder.setTitle(mPrompt);
|
||||
}
|
||||
mPopup = builder.setSingleChoiceItems(mListAdapter,
|
||||
getSelectedItemPosition(), this).show();
|
||||
}
|
||||
|
||||
public void onClick(DialogInterface dialog, int which) {
|
||||
setSelection(which);
|
||||
dismiss();
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
private class DropdownPopup extends IcsListPopupWindow implements SpinnerPopup {
|
||||
private CharSequence mHintText;
|
||||
private ListAdapter mAdapter;
|
||||
|
||||
public DropdownPopup(Context context, AttributeSet attrs, int defStyleRes) {
|
||||
super(context, attrs, 0, defStyleRes);
|
||||
|
||||
setAnchorView(IcsSpinner.this);
|
||||
setModal(true);
|
||||
setPromptPosition(POSITION_PROMPT_ABOVE);
|
||||
setOnItemClickListener(new OnItemClickListener() {
|
||||
@SuppressWarnings("rawtypes")
|
||||
public void onItemClick(AdapterView parent, View v, int position, long id) {
|
||||
IcsSpinner.this.setSelection(position);
|
||||
dismiss();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setAdapter(ListAdapter adapter) {
|
||||
super.setAdapter(adapter);
|
||||
mAdapter = adapter;
|
||||
}
|
||||
|
||||
public CharSequence getHintText() {
|
||||
return mHintText;
|
||||
}
|
||||
|
||||
public void setPromptText(CharSequence hintText) {
|
||||
// Hint text is ignored for dropdowns, but maintain it here.
|
||||
mHintText = hintText;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void show() {
|
||||
final int spinnerPaddingLeft = IcsSpinner.this.getPaddingLeft();
|
||||
if (mDropDownWidth == WRAP_CONTENT) {
|
||||
final int spinnerWidth = IcsSpinner.this.getWidth();
|
||||
final int spinnerPaddingRight = IcsSpinner.this.getPaddingRight();
|
||||
setContentWidth(Math.max(
|
||||
measureContentWidth((SpinnerAdapter) mAdapter, getBackground()),
|
||||
spinnerWidth - spinnerPaddingLeft - spinnerPaddingRight));
|
||||
} else if (mDropDownWidth == MATCH_PARENT) {
|
||||
final int spinnerWidth = IcsSpinner.this.getWidth();
|
||||
final int spinnerPaddingRight = IcsSpinner.this.getPaddingRight();
|
||||
setContentWidth(spinnerWidth - spinnerPaddingLeft - spinnerPaddingRight);
|
||||
} else {
|
||||
setContentWidth(mDropDownWidth);
|
||||
}
|
||||
final Drawable background = getBackground();
|
||||
int bgOffset = 0;
|
||||
if (background != null) {
|
||||
background.getPadding(mTempRect);
|
||||
bgOffset = -mTempRect.left;
|
||||
}
|
||||
setHorizontalOffset(bgOffset + spinnerPaddingLeft);
|
||||
setInputMethodMode(PopupWindow.INPUT_METHOD_NOT_NEEDED);
|
||||
super.show();
|
||||
getListView().setChoiceMode(ListView.CHOICE_MODE_SINGLE);
|
||||
setSelection(IcsSpinner.this.getSelectedItemPosition());
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,60 +0,0 @@
|
|||
|
||||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
import android.view.Gravity;
|
||||
import android.os.Build.VERSION;
|
||||
import android.os.Build.VERSION_CODES;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import com.actionbarsherlock.R;
|
||||
|
||||
public class IcsToast extends Toast {
|
||||
public static final int LENGTH_LONG = Toast.LENGTH_LONG;
|
||||
public static final int LENGTH_SHORT = Toast.LENGTH_SHORT;
|
||||
private static final String TAG = "Toast";
|
||||
|
||||
public static Toast makeText(Context context, CharSequence s, int duration) {
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
return Toast.makeText(context, s, duration);
|
||||
}
|
||||
IcsToast toast = new IcsToast(context);
|
||||
toast.setDuration(duration);
|
||||
TextView view = new TextView(context);
|
||||
view.setText(s);
|
||||
// Original AOSP using reference on @android:color/bright_foreground_dark
|
||||
// bright_foreground_dark - reference on @android:color/background_light
|
||||
// background_light - 0xffffffff
|
||||
view.setTextColor(0xffffffff);
|
||||
view.setGravity(Gravity.CENTER);
|
||||
view.setBackgroundResource(R.drawable.abs__toast_frame);
|
||||
toast.setView(view);
|
||||
return toast;
|
||||
}
|
||||
|
||||
public static Toast makeText(Context context, int resId, int duration) {
|
||||
return makeText(context, context.getResources().getString(resId), duration);
|
||||
}
|
||||
|
||||
public IcsToast(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setText(CharSequence s) {
|
||||
if (VERSION.SDK_INT >= VERSION_CODES.ICE_CREAM_SANDWICH) {
|
||||
super.setText(s);
|
||||
return;
|
||||
}
|
||||
if (getView() == null) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
((TextView) getView()).setText(s);
|
||||
} catch (ClassCastException e) {
|
||||
Log.e(TAG, "This Toast was not created with IcsToast.makeText", e);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,21 +0,0 @@
|
|||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
final class IcsView {
|
||||
//No instances
|
||||
private IcsView() {}
|
||||
|
||||
/**
|
||||
* Return only the state bits of {@link #getMeasuredWidthAndState()}
|
||||
* and {@link #getMeasuredHeightAndState()}, combined into one integer.
|
||||
* The width component is in the regular bits {@link #MEASURED_STATE_MASK}
|
||||
* and the height component is at the shifted bits
|
||||
* {@link #MEASURED_HEIGHT_STATE_SHIFT}>>{@link #MEASURED_STATE_MASK}.
|
||||
*/
|
||||
public static int getMeasuredStateInt(View child) {
|
||||
return (child.getMeasuredWidth()&View.MEASURED_STATE_MASK)
|
||||
| ((child.getMeasuredHeight()>>View.MEASURED_HEIGHT_STATE_SHIFT)
|
||||
& (View.MEASURED_STATE_MASK>>View.MEASURED_HEIGHT_STATE_SHIFT));
|
||||
}
|
||||
}
|
|
@ -1,546 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.Configuration;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.text.TextUtils.TruncateAt;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.Gravity;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
import android.view.animation.DecelerateInterpolator;
|
||||
import android.view.animation.Interpolator;
|
||||
import android.widget.BaseAdapter;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ListView;
|
||||
import com.actionbarsherlock.R;
|
||||
import com.actionbarsherlock.app.ActionBar;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.Animator;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.animation.ObjectAnimator;
|
||||
import com.actionbarsherlock.internal.nineoldandroids.widget.NineHorizontalScrollView;
|
||||
|
||||
/**
|
||||
* This widget implements the dynamic action bar tab behavior that can change
|
||||
* across different configurations or circumstances.
|
||||
*/
|
||||
public class ScrollingTabContainerView extends NineHorizontalScrollView
|
||||
implements IcsAdapterView.OnItemSelectedListener {
|
||||
//UNUSED private static final String TAG = "ScrollingTabContainerView";
|
||||
Runnable mTabSelector;
|
||||
private TabClickListener mTabClickListener;
|
||||
|
||||
private IcsLinearLayout mTabLayout;
|
||||
private IcsSpinner mTabSpinner;
|
||||
private boolean mAllowCollapse;
|
||||
|
||||
private LayoutInflater mInflater;
|
||||
|
||||
int mMaxTabWidth;
|
||||
private int mContentHeight;
|
||||
private int mSelectedTabIndex;
|
||||
|
||||
protected Animator mVisibilityAnim;
|
||||
protected final VisibilityAnimListener mVisAnimListener = new VisibilityAnimListener();
|
||||
|
||||
private static final /*Time*/Interpolator sAlphaInterpolator = new DecelerateInterpolator();
|
||||
|
||||
private static final int FADE_DURATION = 200;
|
||||
|
||||
public ScrollingTabContainerView(Context context) {
|
||||
super(context);
|
||||
setHorizontalScrollBarEnabled(false);
|
||||
|
||||
TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.SherlockActionBar,
|
||||
R.attr.actionBarStyle, 0);
|
||||
setContentHeight(a.getLayoutDimension(R.styleable.SherlockActionBar_height, 0));
|
||||
a.recycle();
|
||||
|
||||
mInflater = LayoutInflater.from(context);
|
||||
|
||||
mTabLayout = createTabLayout();
|
||||
addView(mTabLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
final int widthMode = MeasureSpec.getMode(widthMeasureSpec);
|
||||
final boolean lockedExpanded = widthMode == MeasureSpec.EXACTLY;
|
||||
setFillViewport(lockedExpanded);
|
||||
|
||||
final int childCount = mTabLayout.getChildCount();
|
||||
if (childCount > 1 &&
|
||||
(widthMode == MeasureSpec.EXACTLY || widthMode == MeasureSpec.AT_MOST)) {
|
||||
if (childCount > 2) {
|
||||
mMaxTabWidth = (int) (MeasureSpec.getSize(widthMeasureSpec) * 0.4f);
|
||||
} else {
|
||||
mMaxTabWidth = MeasureSpec.getSize(widthMeasureSpec) / 2;
|
||||
}
|
||||
} else {
|
||||
mMaxTabWidth = -1;
|
||||
}
|
||||
|
||||
heightMeasureSpec = MeasureSpec.makeMeasureSpec(mContentHeight, MeasureSpec.EXACTLY);
|
||||
|
||||
final boolean canCollapse = !lockedExpanded && mAllowCollapse;
|
||||
|
||||
if (canCollapse) {
|
||||
// See if we should expand
|
||||
mTabLayout.measure(MeasureSpec.UNSPECIFIED, heightMeasureSpec);
|
||||
if (mTabLayout.getMeasuredWidth() > MeasureSpec.getSize(widthMeasureSpec)) {
|
||||
performCollapse();
|
||||
} else {
|
||||
performExpand();
|
||||
}
|
||||
} else {
|
||||
performExpand();
|
||||
}
|
||||
|
||||
final int oldWidth = getMeasuredWidth();
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
final int newWidth = getMeasuredWidth();
|
||||
|
||||
if (lockedExpanded && oldWidth != newWidth) {
|
||||
// Recenter the tab display if we're at a new (scrollable) size.
|
||||
setTabSelected(mSelectedTabIndex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Indicates whether this view is collapsed into a dropdown menu instead
|
||||
* of traditional tabs.
|
||||
* @return true if showing as a spinner
|
||||
*/
|
||||
private boolean isCollapsed() {
|
||||
return mTabSpinner != null && mTabSpinner.getParent() == this;
|
||||
}
|
||||
|
||||
public void setAllowCollapse(boolean allowCollapse) {
|
||||
mAllowCollapse = allowCollapse;
|
||||
}
|
||||
|
||||
private void performCollapse() {
|
||||
if (isCollapsed()) return;
|
||||
|
||||
if (mTabSpinner == null) {
|
||||
mTabSpinner = createSpinner();
|
||||
}
|
||||
removeView(mTabLayout);
|
||||
addView(mTabSpinner, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
if (mTabSpinner.getAdapter() == null) {
|
||||
mTabSpinner.setAdapter(new TabAdapter());
|
||||
}
|
||||
if (mTabSelector != null) {
|
||||
removeCallbacks(mTabSelector);
|
||||
mTabSelector = null;
|
||||
}
|
||||
mTabSpinner.setSelection(mSelectedTabIndex);
|
||||
}
|
||||
|
||||
private boolean performExpand() {
|
||||
if (!isCollapsed()) return false;
|
||||
|
||||
removeView(mTabSpinner);
|
||||
addView(mTabLayout, new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
|
||||
ViewGroup.LayoutParams.MATCH_PARENT));
|
||||
setTabSelected(mTabSpinner.getSelectedItemPosition());
|
||||
return false;
|
||||
}
|
||||
|
||||
public void setTabSelected(int position) {
|
||||
mSelectedTabIndex = position;
|
||||
final int tabCount = mTabLayout.getChildCount();
|
||||
for (int i = 0; i < tabCount; i++) {
|
||||
final View child = mTabLayout.getChildAt(i);
|
||||
final boolean isSelected = i == position;
|
||||
child.setSelected(isSelected);
|
||||
if (isSelected) {
|
||||
animateToTab(position);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void setContentHeight(int contentHeight) {
|
||||
mContentHeight = contentHeight;
|
||||
requestLayout();
|
||||
}
|
||||
|
||||
private IcsLinearLayout createTabLayout() {
|
||||
final TabsLinearLayout tabLayout = (TabsLinearLayout) LayoutInflater.from(getContext())
|
||||
.inflate(R.layout.abs__action_bar_tab_bar_view, null);
|
||||
tabLayout.setMeasureWithLargestChildEnabled(true);
|
||||
tabLayout.setLayoutParams(new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT));
|
||||
return tabLayout;
|
||||
}
|
||||
|
||||
private IcsSpinner createSpinner() {
|
||||
final IcsSpinner spinner = new IcsSpinner(getContext(), null,
|
||||
R.attr.actionDropDownStyle);
|
||||
spinner.setLayoutParams(new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.MATCH_PARENT));
|
||||
spinner.setOnItemSelectedListener(this);
|
||||
return spinner;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onConfigurationChanged(Configuration newConfig) {
|
||||
super.onConfigurationChanged(newConfig);
|
||||
|
||||
// Action bar can change size on configuration changes.
|
||||
// Reread the desired height from the theme-specified style.
|
||||
TypedArray a = getContext().obtainStyledAttributes(null, R.styleable.SherlockActionBar,
|
||||
R.attr.actionBarStyle, 0);
|
||||
setContentHeight(a.getLayoutDimension(R.styleable.SherlockActionBar_height, 0));
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
public void animateToVisibility(int visibility) {
|
||||
if (mVisibilityAnim != null) {
|
||||
mVisibilityAnim.cancel();
|
||||
}
|
||||
if (visibility == VISIBLE) {
|
||||
if (getVisibility() != VISIBLE) {
|
||||
setAlpha(0);
|
||||
}
|
||||
ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 1);
|
||||
anim.setDuration(FADE_DURATION);
|
||||
anim.setInterpolator(sAlphaInterpolator);
|
||||
|
||||
anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
|
||||
anim.start();
|
||||
} else {
|
||||
ObjectAnimator anim = ObjectAnimator.ofFloat(this, "alpha", 0);
|
||||
anim.setDuration(FADE_DURATION);
|
||||
anim.setInterpolator(sAlphaInterpolator);
|
||||
|
||||
anim.addListener(mVisAnimListener.withFinalVisibility(visibility));
|
||||
anim.start();
|
||||
}
|
||||
}
|
||||
|
||||
public void animateToTab(final int position) {
|
||||
final View tabView = mTabLayout.getChildAt(position);
|
||||
if (mTabSelector != null) {
|
||||
removeCallbacks(mTabSelector);
|
||||
}
|
||||
mTabSelector = new Runnable() {
|
||||
public void run() {
|
||||
final int scrollPos = tabView.getLeft() - (getWidth() - tabView.getWidth()) / 2;
|
||||
smoothScrollTo(scrollPos, 0);
|
||||
mTabSelector = null;
|
||||
}
|
||||
};
|
||||
post(mTabSelector);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAttachedToWindow() {
|
||||
super.onAttachedToWindow();
|
||||
if (mTabSelector != null) {
|
||||
// Re-post the selector we saved
|
||||
post(mTabSelector);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
if (mTabSelector != null) {
|
||||
removeCallbacks(mTabSelector);
|
||||
}
|
||||
}
|
||||
|
||||
private TabView createTabView(ActionBar.Tab tab, boolean forAdapter) {
|
||||
//Workaround for not being able to pass a defStyle on pre-3.0
|
||||
final TabView tabView = (TabView)mInflater.inflate(R.layout.abs__action_bar_tab, null);
|
||||
tabView.init(this, tab, forAdapter);
|
||||
|
||||
if (forAdapter) {
|
||||
tabView.setBackgroundDrawable(null);
|
||||
tabView.setLayoutParams(new ListView.LayoutParams(ListView.LayoutParams.MATCH_PARENT,
|
||||
mContentHeight));
|
||||
} else {
|
||||
tabView.setFocusable(true);
|
||||
|
||||
if (mTabClickListener == null) {
|
||||
mTabClickListener = new TabClickListener();
|
||||
}
|
||||
tabView.setOnClickListener(mTabClickListener);
|
||||
}
|
||||
return tabView;
|
||||
}
|
||||
|
||||
public void addTab(ActionBar.Tab tab, boolean setSelected) {
|
||||
TabView tabView = createTabView(tab, false);
|
||||
mTabLayout.addView(tabView, new IcsLinearLayout.LayoutParams(0,
|
||||
LayoutParams.MATCH_PARENT, 1));
|
||||
if (mTabSpinner != null) {
|
||||
((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
|
||||
}
|
||||
if (setSelected) {
|
||||
tabView.setSelected(true);
|
||||
}
|
||||
if (mAllowCollapse) {
|
||||
requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
public void addTab(ActionBar.Tab tab, int position, boolean setSelected) {
|
||||
final TabView tabView = createTabView(tab, false);
|
||||
mTabLayout.addView(tabView, position, new IcsLinearLayout.LayoutParams(
|
||||
0, LayoutParams.MATCH_PARENT, 1));
|
||||
if (mTabSpinner != null) {
|
||||
((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
|
||||
}
|
||||
if (setSelected) {
|
||||
tabView.setSelected(true);
|
||||
}
|
||||
if (mAllowCollapse) {
|
||||
requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
public void updateTab(int position) {
|
||||
((TabView) mTabLayout.getChildAt(position)).update();
|
||||
if (mTabSpinner != null) {
|
||||
((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
|
||||
}
|
||||
if (mAllowCollapse) {
|
||||
requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeTabAt(int position) {
|
||||
mTabLayout.removeViewAt(position);
|
||||
if (mTabSpinner != null) {
|
||||
((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
|
||||
}
|
||||
if (mAllowCollapse) {
|
||||
requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
public void removeAllTabs() {
|
||||
mTabLayout.removeAllViews();
|
||||
if (mTabSpinner != null) {
|
||||
((TabAdapter) mTabSpinner.getAdapter()).notifyDataSetChanged();
|
||||
}
|
||||
if (mAllowCollapse) {
|
||||
requestLayout();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onItemSelected(IcsAdapterView<?> parent, View view, int position, long id) {
|
||||
TabView tabView = (TabView) view;
|
||||
tabView.getTab().select();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(IcsAdapterView<?> parent) {
|
||||
}
|
||||
|
||||
public static class TabView extends LinearLayout {
|
||||
private ScrollingTabContainerView mParent;
|
||||
private ActionBar.Tab mTab;
|
||||
private CapitalizingTextView mTextView;
|
||||
private ImageView mIconView;
|
||||
private View mCustomView;
|
||||
|
||||
public TabView(Context context, AttributeSet attrs) {
|
||||
//TODO super(context, null, R.attr.actionBarTabStyle);
|
||||
super(context, attrs);
|
||||
}
|
||||
|
||||
public void init(ScrollingTabContainerView parent, ActionBar.Tab tab, boolean forList) {
|
||||
mParent = parent;
|
||||
mTab = tab;
|
||||
|
||||
if (forList) {
|
||||
setGravity(Gravity.LEFT | Gravity.CENTER_VERTICAL);
|
||||
}
|
||||
|
||||
update();
|
||||
}
|
||||
|
||||
public void bindTab(ActionBar.Tab tab) {
|
||||
mTab = tab;
|
||||
update();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
// Re-measure if we went beyond our maximum size.
|
||||
if (mParent.mMaxTabWidth > 0 && getMeasuredWidth() > mParent.mMaxTabWidth) {
|
||||
super.onMeasure(MeasureSpec.makeMeasureSpec(mParent.mMaxTabWidth, MeasureSpec.EXACTLY),
|
||||
heightMeasureSpec);
|
||||
}
|
||||
}
|
||||
|
||||
public void update() {
|
||||
final ActionBar.Tab tab = mTab;
|
||||
final View custom = tab.getCustomView();
|
||||
if (custom != null) {
|
||||
final ViewParent customParent = custom.getParent();
|
||||
if (customParent != this) {
|
||||
if (customParent != null) ((ViewGroup) customParent).removeView(custom);
|
||||
addView(custom);
|
||||
}
|
||||
mCustomView = custom;
|
||||
if (mTextView != null) mTextView.setVisibility(GONE);
|
||||
if (mIconView != null) {
|
||||
mIconView.setVisibility(GONE);
|
||||
mIconView.setImageDrawable(null);
|
||||
}
|
||||
} else {
|
||||
if (mCustomView != null) {
|
||||
removeView(mCustomView);
|
||||
mCustomView = null;
|
||||
}
|
||||
|
||||
final Drawable icon = tab.getIcon();
|
||||
final CharSequence text = tab.getText();
|
||||
|
||||
if (icon != null) {
|
||||
if (mIconView == null) {
|
||||
ImageView iconView = new ImageView(getContext());
|
||||
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
|
||||
LayoutParams.WRAP_CONTENT);
|
||||
lp.gravity = Gravity.CENTER_VERTICAL;
|
||||
iconView.setLayoutParams(lp);
|
||||
addView(iconView, 0);
|
||||
mIconView = iconView;
|
||||
}
|
||||
mIconView.setImageDrawable(icon);
|
||||
mIconView.setVisibility(VISIBLE);
|
||||
} else if (mIconView != null) {
|
||||
mIconView.setVisibility(GONE);
|
||||
mIconView.setImageDrawable(null);
|
||||
}
|
||||
|
||||
if (text != null) {
|
||||
if (mTextView == null) {
|
||||
CapitalizingTextView textView = new CapitalizingTextView(getContext(), null,
|
||||
R.attr.actionBarTabTextStyle);
|
||||
textView.setEllipsize(TruncateAt.END);
|
||||
LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
|
||||
LayoutParams.WRAP_CONTENT);
|
||||
lp.gravity = Gravity.CENTER_VERTICAL;
|
||||
textView.setLayoutParams(lp);
|
||||
addView(textView);
|
||||
mTextView = textView;
|
||||
}
|
||||
mTextView.setTextCompat(text);
|
||||
mTextView.setVisibility(VISIBLE);
|
||||
} else if (mTextView != null) {
|
||||
mTextView.setVisibility(GONE);
|
||||
mTextView.setText(null);
|
||||
}
|
||||
|
||||
if (mIconView != null) {
|
||||
mIconView.setContentDescription(tab.getContentDescription());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ActionBar.Tab getTab() {
|
||||
return mTab;
|
||||
}
|
||||
}
|
||||
|
||||
private class TabAdapter extends BaseAdapter {
|
||||
@Override
|
||||
public int getCount() {
|
||||
return mTabLayout.getChildCount();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Object getItem(int position) {
|
||||
return ((TabView) mTabLayout.getChildAt(position)).getTab();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getItemId(int position) {
|
||||
return position;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
if (convertView == null) {
|
||||
convertView = createTabView((ActionBar.Tab) getItem(position), true);
|
||||
} else {
|
||||
((TabView) convertView).bindTab((ActionBar.Tab) getItem(position));
|
||||
}
|
||||
return convertView;
|
||||
}
|
||||
}
|
||||
|
||||
private class TabClickListener implements OnClickListener {
|
||||
public void onClick(View view) {
|
||||
TabView tabView = (TabView) view;
|
||||
tabView.getTab().select();
|
||||
final int tabCount = mTabLayout.getChildCount();
|
||||
for (int i = 0; i < tabCount; i++) {
|
||||
final View child = mTabLayout.getChildAt(i);
|
||||
child.setSelected(child == view);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected class VisibilityAnimListener implements Animator.AnimatorListener {
|
||||
private boolean mCanceled = false;
|
||||
private int mFinalVisibility;
|
||||
|
||||
public VisibilityAnimListener withFinalVisibility(int visibility) {
|
||||
mFinalVisibility = visibility;
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationStart(Animator animation) {
|
||||
setVisibility(VISIBLE);
|
||||
mVisibilityAnim = animation;
|
||||
mCanceled = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationEnd(Animator animation) {
|
||||
if (mCanceled) return;
|
||||
|
||||
mVisibilityAnim = null;
|
||||
setVisibility(mFinalVisibility);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationCancel(Animator animation) {
|
||||
mCanceled = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onAnimationRepeat(Animator animation) {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,113 +0,0 @@
|
|||
package com.actionbarsherlock.internal.widget;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.util.AttributeSet;
|
||||
import android.view.View;
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
public class TabsLinearLayout extends IcsLinearLayout {
|
||||
private static final int[] R_styleable_LinearLayout = new int[] {
|
||||
/* 0 */ android.R.attr.measureWithLargestChild,
|
||||
};
|
||||
private static final int LinearLayout_measureWithLargestChild = 0;
|
||||
|
||||
private boolean mUseLargestChild;
|
||||
|
||||
public TabsLinearLayout(Context context, AttributeSet attrs) {
|
||||
super(context, attrs);
|
||||
|
||||
TypedArray a = context.obtainStyledAttributes(attrs, /*com.android.internal.R.styleable.*/R_styleable_LinearLayout);
|
||||
mUseLargestChild = a.getBoolean(/*com.android.internal.R.styleable.*/LinearLayout_measureWithLargestChild, false);
|
||||
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
/**
|
||||
* When true, all children with a weight will be considered having
|
||||
* the minimum size of the largest child. If false, all children are
|
||||
* measured normally.
|
||||
*
|
||||
* @return True to measure children with a weight using the minimum
|
||||
* size of the largest child, false otherwise.
|
||||
*
|
||||
* @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
|
||||
*/
|
||||
public boolean isMeasureWithLargestChildEnabled() {
|
||||
return mUseLargestChild;
|
||||
}
|
||||
|
||||
/**
|
||||
* When set to true, all children with a weight will be considered having
|
||||
* the minimum size of the largest child. If false, all children are
|
||||
* measured normally.
|
||||
*
|
||||
* Disabled by default.
|
||||
*
|
||||
* @param enabled True to measure children with a weight using the
|
||||
* minimum size of the largest child, false otherwise.
|
||||
*
|
||||
* @attr ref android.R.styleable#LinearLayout_measureWithLargestChild
|
||||
*/
|
||||
public void setMeasureWithLargestChildEnabled(boolean enabled) {
|
||||
mUseLargestChild = enabled;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
|
||||
|
||||
final int childCount = getChildCount();
|
||||
if (childCount <= 2) return;
|
||||
|
||||
final int mode = MeasureSpec.getMode(widthMeasureSpec);
|
||||
if (mUseLargestChild && mode == MeasureSpec.UNSPECIFIED) {
|
||||
final int orientation = getOrientation();
|
||||
if (orientation == HORIZONTAL) {
|
||||
useLargestChildHorizontal();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void useLargestChildHorizontal() {
|
||||
final int childCount = getChildCount();
|
||||
|
||||
// Find largest child width
|
||||
int largestChildWidth = 0;
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = getChildAt(i);
|
||||
largestChildWidth = Math.max(child.getMeasuredWidth(), largestChildWidth);
|
||||
}
|
||||
|
||||
int totalWidth = 0;
|
||||
// Re-measure childs
|
||||
for (int i = 0; i < childCount; i++) {
|
||||
final View child = getChildAt(i);
|
||||
|
||||
if (child == null || child.getVisibility() == View.GONE) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final LinearLayout.LayoutParams lp =
|
||||
(LinearLayout.LayoutParams) child.getLayoutParams();
|
||||
|
||||
float childExtra = lp.weight;
|
||||
if (childExtra > 0) {
|
||||
child.measure(
|
||||
MeasureSpec.makeMeasureSpec(largestChildWidth,
|
||||
MeasureSpec.EXACTLY),
|
||||
MeasureSpec.makeMeasureSpec(child.getMeasuredHeight(),
|
||||
MeasureSpec.EXACTLY));
|
||||
totalWidth += largestChildWidth;
|
||||
|
||||
} else {
|
||||
totalWidth += child.getMeasuredWidth();
|
||||
}
|
||||
|
||||
totalWidth += lp.leftMargin + lp.rightMargin;
|
||||
}
|
||||
|
||||
totalWidth += getPaddingLeft() + getPaddingRight();
|
||||
setMeasuredDimension(totalWidth, getMeasuredHeight());
|
||||
}
|
||||
}
|
|
@ -1,224 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2010 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.view;
|
||||
|
||||
import android.view.View;
|
||||
|
||||
|
||||
/**
|
||||
* Represents a contextual mode of the user interface. Action modes can be used for
|
||||
* modal interactions with content and replace parts of the normal UI until finished.
|
||||
* Examples of good action modes include selection modes, search, content editing, etc.
|
||||
*/
|
||||
public abstract class ActionMode {
|
||||
private Object mTag;
|
||||
|
||||
/**
|
||||
* Set a tag object associated with this ActionMode.
|
||||
*
|
||||
* <p>Like the tag available to views, this allows applications to associate arbitrary
|
||||
* data with an ActionMode for later reference.
|
||||
*
|
||||
* @param tag Tag to associate with this ActionMode
|
||||
*
|
||||
* @see #getTag()
|
||||
*/
|
||||
public void setTag(Object tag) {
|
||||
mTag = tag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the tag object associated with this ActionMode.
|
||||
*
|
||||
* <p>Like the tag available to views, this allows applications to associate arbitrary
|
||||
* data with an ActionMode for later reference.
|
||||
*
|
||||
* @return Tag associated with this ActionMode
|
||||
*
|
||||
* @see #setTag(Object)
|
||||
*/
|
||||
public Object getTag() {
|
||||
return mTag;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the title of the action mode. This method will have no visible effect if
|
||||
* a custom view has been set.
|
||||
*
|
||||
* @param title Title string to set
|
||||
*
|
||||
* @see #setTitle(int)
|
||||
* @see #setCustomView(View)
|
||||
*/
|
||||
public abstract void setTitle(CharSequence title);
|
||||
|
||||
/**
|
||||
* Set the title of the action mode. This method will have no visible effect if
|
||||
* a custom view has been set.
|
||||
*
|
||||
* @param resId Resource ID of a string to set as the title
|
||||
*
|
||||
* @see #setTitle(CharSequence)
|
||||
* @see #setCustomView(View)
|
||||
*/
|
||||
public abstract void setTitle(int resId);
|
||||
|
||||
/**
|
||||
* Set the subtitle of the action mode. This method will have no visible effect if
|
||||
* a custom view has been set.
|
||||
*
|
||||
* @param subtitle Subtitle string to set
|
||||
*
|
||||
* @see #setSubtitle(int)
|
||||
* @see #setCustomView(View)
|
||||
*/
|
||||
public abstract void setSubtitle(CharSequence subtitle);
|
||||
|
||||
/**
|
||||
* Set the subtitle of the action mode. This method will have no visible effect if
|
||||
* a custom view has been set.
|
||||
*
|
||||
* @param resId Resource ID of a string to set as the subtitle
|
||||
*
|
||||
* @see #setSubtitle(CharSequence)
|
||||
* @see #setCustomView(View)
|
||||
*/
|
||||
public abstract void setSubtitle(int resId);
|
||||
|
||||
/**
|
||||
* Set a custom view for this action mode. The custom view will take the place of
|
||||
* the title and subtitle. Useful for things like search boxes.
|
||||
*
|
||||
* @param view Custom view to use in place of the title/subtitle.
|
||||
*
|
||||
* @see #setTitle(CharSequence)
|
||||
* @see #setSubtitle(CharSequence)
|
||||
*/
|
||||
public abstract void setCustomView(View view);
|
||||
|
||||
/**
|
||||
* Invalidate the action mode and refresh menu content. The mode's
|
||||
* {@link ActionMode.Callback} will have its
|
||||
* {@link Callback#onPrepareActionMode(ActionMode, Menu)} method called.
|
||||
* If it returns true the menu will be scanned for updated content and any relevant changes
|
||||
* will be reflected to the user.
|
||||
*/
|
||||
public abstract void invalidate();
|
||||
|
||||
/**
|
||||
* Finish and close this action mode. The action mode's {@link ActionMode.Callback} will
|
||||
* have its {@link Callback#onDestroyActionMode(ActionMode)} method called.
|
||||
*/
|
||||
public abstract void finish();
|
||||
|
||||
/**
|
||||
* Returns the menu of actions that this action mode presents.
|
||||
* @return The action mode's menu.
|
||||
*/
|
||||
public abstract Menu getMenu();
|
||||
|
||||
/**
|
||||
* Returns the current title of this action mode.
|
||||
* @return Title text
|
||||
*/
|
||||
public abstract CharSequence getTitle();
|
||||
|
||||
/**
|
||||
* Returns the current subtitle of this action mode.
|
||||
* @return Subtitle text
|
||||
*/
|
||||
public abstract CharSequence getSubtitle();
|
||||
|
||||
/**
|
||||
* Returns the current custom view for this action mode.
|
||||
* @return The current custom view
|
||||
*/
|
||||
public abstract View getCustomView();
|
||||
|
||||
/**
|
||||
* Returns a {@link MenuInflater} with the ActionMode's context.
|
||||
*/
|
||||
public abstract MenuInflater getMenuInflater();
|
||||
|
||||
/**
|
||||
* Returns whether the UI presenting this action mode can take focus or not.
|
||||
* This is used by internal components within the framework that would otherwise
|
||||
* present an action mode UI that requires focus, such as an EditText as a custom view.
|
||||
*
|
||||
* @return true if the UI used to show this action mode can take focus
|
||||
* @hide Internal use only
|
||||
*/
|
||||
public boolean isUiFocusable() {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback interface for action modes. Supplied to
|
||||
* {@link View#startActionMode(Callback)}, a Callback
|
||||
* configures and handles events raised by a user's interaction with an action mode.
|
||||
*
|
||||
* <p>An action mode's lifecycle is as follows:
|
||||
* <ul>
|
||||
* <li>{@link Callback#onCreateActionMode(ActionMode, Menu)} once on initial
|
||||
* creation</li>
|
||||
* <li>{@link Callback#onPrepareActionMode(ActionMode, Menu)} after creation
|
||||
* and any time the {@link ActionMode} is invalidated</li>
|
||||
* <li>{@link Callback#onActionItemClicked(ActionMode, MenuItem)} any time a
|
||||
* contextual action button is clicked</li>
|
||||
* <li>{@link Callback#onDestroyActionMode(ActionMode)} when the action mode
|
||||
* is closed</li>
|
||||
* </ul>
|
||||
*/
|
||||
public interface Callback {
|
||||
/**
|
||||
* Called when action mode is first created. The menu supplied will be used to
|
||||
* generate action buttons for the action mode.
|
||||
*
|
||||
* @param mode ActionMode being created
|
||||
* @param menu Menu used to populate action buttons
|
||||
* @return true if the action mode should be created, false if entering this
|
||||
* mode should be aborted.
|
||||
*/
|
||||
public boolean onCreateActionMode(ActionMode mode, Menu menu);
|
||||
|
||||
/**
|
||||
* Called to refresh an action mode's action menu whenever it is invalidated.
|
||||
*
|
||||
* @param mode ActionMode being prepared
|
||||
* @param menu Menu used to populate action buttons
|
||||
* @return true if the menu or action mode was updated, false otherwise.
|
||||
*/
|
||||
public boolean onPrepareActionMode(ActionMode mode, Menu menu);
|
||||
|
||||
/**
|
||||
* Called to report a user click on an action button.
|
||||
*
|
||||
* @param mode The current ActionMode
|
||||
* @param item The item that was clicked
|
||||
* @return true if this callback handled the event, false if the standard MenuItem
|
||||
* invocation should continue.
|
||||
*/
|
||||
public boolean onActionItemClicked(ActionMode mode, MenuItem item);
|
||||
|
||||
/**
|
||||
* Called when an action mode is about to be exited and destroyed.
|
||||
*
|
||||
* @param mode The current ActionMode being destroyed
|
||||
*/
|
||||
public void onDestroyActionMode(ActionMode mode);
|
||||
}
|
||||
}
|
|
@ -1,170 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.view;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* This class is a mediator for accomplishing a given task, for example sharing a file.
|
||||
* It is responsible for creating a view that performs an action that accomplishes the task.
|
||||
* This class also implements other functions such a performing a default action.
|
||||
* <p>
|
||||
* An ActionProvider can be optionally specified for a {@link MenuItem} and in such a
|
||||
* case it will be responsible for creating the action view that appears in the
|
||||
* {@link android.app.ActionBar} as a substitute for the menu item when the item is
|
||||
* displayed as an action item. Also the provider is responsible for performing a
|
||||
* default action if a menu item placed on the overflow menu of the ActionBar is
|
||||
* selected and none of the menu item callbacks has handled the selection. For this
|
||||
* case the provider can also optionally provide a sub-menu for accomplishing the
|
||||
* task at hand.
|
||||
* </p>
|
||||
* <p>
|
||||
* There are two ways for using an action provider for creating and handling of action views:
|
||||
* <ul>
|
||||
* <li>
|
||||
* Setting the action provider on a {@link MenuItem} directly by calling
|
||||
* {@link MenuItem#setActionProvider(ActionProvider)}.
|
||||
* </li>
|
||||
* <li>
|
||||
* Declaring the action provider in the menu XML resource. For example:
|
||||
* <pre>
|
||||
* <code>
|
||||
* <item android:id="@+id/my_menu_item"
|
||||
* android:title="Title"
|
||||
* android:icon="@drawable/my_menu_item_icon"
|
||||
* android:showAsAction="ifRoom"
|
||||
* android:actionProviderClass="foo.bar.SomeActionProvider" />
|
||||
* </code>
|
||||
* </pre>
|
||||
* </li>
|
||||
* </ul>
|
||||
* </p>
|
||||
*
|
||||
* @see MenuItem#setActionProvider(ActionProvider)
|
||||
* @see MenuItem#getActionProvider()
|
||||
*/
|
||||
public abstract class ActionProvider {
|
||||
private SubUiVisibilityListener mSubUiVisibilityListener;
|
||||
|
||||
/**
|
||||
* Creates a new instance.
|
||||
*
|
||||
* @param context Context for accessing resources.
|
||||
*/
|
||||
public ActionProvider(Context context) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method for creating new action views.
|
||||
*
|
||||
* @return A new action view.
|
||||
*/
|
||||
public abstract View onCreateActionView();
|
||||
|
||||
/**
|
||||
* Performs an optional default action.
|
||||
* <p>
|
||||
* For the case of an action provider placed in a menu item not shown as an action this
|
||||
* method is invoked if previous callbacks for processing menu selection has handled
|
||||
* the event.
|
||||
* </p>
|
||||
* <p>
|
||||
* A menu item selection is processed in the following order:
|
||||
* <ul>
|
||||
* <li>
|
||||
* Receiving a call to {@link MenuItem.OnMenuItemClickListener#onMenuItemClick
|
||||
* MenuItem.OnMenuItemClickListener.onMenuItemClick}.
|
||||
* </li>
|
||||
* <li>
|
||||
* Receiving a call to {@link android.app.Activity#onOptionsItemSelected(MenuItem)
|
||||
* Activity.onOptionsItemSelected(MenuItem)}
|
||||
* </li>
|
||||
* <li>
|
||||
* Receiving a call to {@link android.app.Fragment#onOptionsItemSelected(MenuItem)
|
||||
* Fragment.onOptionsItemSelected(MenuItem)}
|
||||
* </li>
|
||||
* <li>
|
||||
* Launching the {@link android.content.Intent} set via
|
||||
* {@link MenuItem#setIntent(android.content.Intent) MenuItem.setIntent(android.content.Intent)}
|
||||
* </li>
|
||||
* <li>
|
||||
* Invoking this method.
|
||||
* </li>
|
||||
* </ul>
|
||||
* </p>
|
||||
* <p>
|
||||
* The default implementation does not perform any action and returns false.
|
||||
* </p>
|
||||
*/
|
||||
public boolean onPerformDefaultAction() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if this ActionProvider has a submenu associated with it.
|
||||
*
|
||||
* <p>Associated submenus will be shown when an action view is not. This
|
||||
* provider instance will receive a call to {@link #onPrepareSubMenu(SubMenu)}
|
||||
* after the call to {@link #onPerformDefaultAction()} and before a submenu is
|
||||
* displayed to the user.
|
||||
*
|
||||
* @return true if the item backed by this provider should have an associated submenu
|
||||
*/
|
||||
public boolean hasSubMenu() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called to prepare an associated submenu for the menu item backed by this ActionProvider.
|
||||
*
|
||||
* <p>if {@link #hasSubMenu()} returns true, this method will be called when the
|
||||
* menu item is selected to prepare the submenu for presentation to the user. Apps
|
||||
* may use this to create or alter submenu content right before display.
|
||||
*
|
||||
* @param subMenu Submenu that will be displayed
|
||||
*/
|
||||
public void onPrepareSubMenu(SubMenu subMenu) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Notify the system that the visibility of an action view's sub-UI such as
|
||||
* an anchored popup has changed. This will affect how other system
|
||||
* visibility notifications occur.
|
||||
*
|
||||
* @hide Pending future API approval
|
||||
*/
|
||||
public void subUiVisibilityChanged(boolean isVisible) {
|
||||
if (mSubUiVisibilityListener != null) {
|
||||
mSubUiVisibilityListener.onSubUiVisibilityChanged(isVisible);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide Internal use only
|
||||
*/
|
||||
public void setSubUiVisibilityListener(SubUiVisibilityListener listener) {
|
||||
mSubUiVisibilityListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* @hide Internal use only
|
||||
*/
|
||||
public interface SubUiVisibilityListener {
|
||||
public void onSubUiVisibilityChanged(boolean isVisible);
|
||||
}
|
||||
}
|
|
@ -1,39 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.view;
|
||||
|
||||
/**
|
||||
* When a {@link View} implements this interface it will receive callbacks
|
||||
* when expanded or collapsed as an action view alongside the optional,
|
||||
* app-specified callbacks to {@link OnActionExpandListener}.
|
||||
*
|
||||
* <p>See {@link MenuItem} for more information about action views.
|
||||
* See {@link android.app.ActionBar} for more information about the action bar.
|
||||
*/
|
||||
public interface CollapsibleActionView {
|
||||
/**
|
||||
* Called when this view is expanded as an action view.
|
||||
* See {@link MenuItem#expandActionView()}.
|
||||
*/
|
||||
public void onActionViewExpanded();
|
||||
|
||||
/**
|
||||
* Called when this view is collapsed as an action view.
|
||||
* See {@link MenuItem#collapseActionView()}.
|
||||
*/
|
||||
public void onActionViewCollapsed();
|
||||
}
|
|
@ -1,446 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.view;
|
||||
|
||||
import android.content.ComponentName;
|
||||
import android.content.Intent;
|
||||
import android.view.KeyEvent;
|
||||
|
||||
/**
|
||||
* Interface for managing the items in a menu.
|
||||
* <p>
|
||||
* By default, every Activity supports an options menu of actions or options.
|
||||
* You can add items to this menu and handle clicks on your additions. The
|
||||
* easiest way of adding menu items is inflating an XML file into the
|
||||
* {@link Menu} via {@link MenuInflater}. The easiest way of attaching code to
|
||||
* clicks is via {@link Activity#onOptionsItemSelected(MenuItem)} and
|
||||
* {@link Activity#onContextItemSelected(MenuItem)}.
|
||||
* <p>
|
||||
* Different menu types support different features:
|
||||
* <ol>
|
||||
* <li><b>Context menus</b>: Do not support item shortcuts and item icons.
|
||||
* <li><b>Options menus</b>: The <b>icon menus</b> do not support item check
|
||||
* marks and only show the item's
|
||||
* {@link MenuItem#setTitleCondensed(CharSequence) condensed title}. The
|
||||
* <b>expanded menus</b> (only available if six or more menu items are visible,
|
||||
* reached via the 'More' item in the icon menu) do not show item icons, and
|
||||
* item check marks are discouraged.
|
||||
* <li><b>Sub menus</b>: Do not support item icons, or nested sub menus.
|
||||
* </ol>
|
||||
*
|
||||
* <div class="special reference">
|
||||
* <h3>Developer Guides</h3>
|
||||
* <p>For more information about creating menus, read the
|
||||
* <a href="{@docRoot}guide/topics/ui/menus.html">Menus</a> developer guide.</p>
|
||||
* </div>
|
||||
*/
|
||||
public interface Menu {
|
||||
|
||||
/**
|
||||
* This is the part of an order integer that the user can provide.
|
||||
* @hide
|
||||
*/
|
||||
static final int USER_MASK = 0x0000ffff;
|
||||
/**
|
||||
* Bit shift of the user portion of the order integer.
|
||||
* @hide
|
||||
*/
|
||||
static final int USER_SHIFT = 0;
|
||||
|
||||
/**
|
||||
* This is the part of an order integer that supplies the category of the
|
||||
* item.
|
||||
* @hide
|
||||
*/
|
||||
static final int CATEGORY_MASK = 0xffff0000;
|
||||
/**
|
||||
* Bit shift of the category portion of the order integer.
|
||||
* @hide
|
||||
*/
|
||||
static final int CATEGORY_SHIFT = 16;
|
||||
|
||||
/**
|
||||
* Value to use for group and item identifier integers when you don't care
|
||||
* about them.
|
||||
*/
|
||||
static final int NONE = 0;
|
||||
|
||||
/**
|
||||
* First value for group and item identifier integers.
|
||||
*/
|
||||
static final int FIRST = 1;
|
||||
|
||||
// Implementation note: Keep these CATEGORY_* in sync with the category enum
|
||||
// in attrs.xml
|
||||
|
||||
/**
|
||||
* Category code for the order integer for items/groups that are part of a
|
||||
* container -- or/add this with your base value.
|
||||
*/
|
||||
static final int CATEGORY_CONTAINER = 0x00010000;
|
||||
|
||||
/**
|
||||
* Category code for the order integer for items/groups that are provided by
|
||||
* the system -- or/add this with your base value.
|
||||
*/
|
||||
static final int CATEGORY_SYSTEM = 0x00020000;
|
||||
|
||||
/**
|
||||
* Category code for the order integer for items/groups that are
|
||||
* user-supplied secondary (infrequently used) options -- or/add this with
|
||||
* your base value.
|
||||
*/
|
||||
static final int CATEGORY_SECONDARY = 0x00030000;
|
||||
|
||||
/**
|
||||
* Category code for the order integer for items/groups that are
|
||||
* alternative actions on the data that is currently displayed -- or/add
|
||||
* this with your base value.
|
||||
*/
|
||||
static final int CATEGORY_ALTERNATIVE = 0x00040000;
|
||||
|
||||
/**
|
||||
* Flag for {@link #addIntentOptions}: if set, do not automatically remove
|
||||
* any existing menu items in the same group.
|
||||
*/
|
||||
static final int FLAG_APPEND_TO_GROUP = 0x0001;
|
||||
|
||||
/**
|
||||
* Flag for {@link #performShortcut}: if set, do not close the menu after
|
||||
* executing the shortcut.
|
||||
*/
|
||||
static final int FLAG_PERFORM_NO_CLOSE = 0x0001;
|
||||
|
||||
/**
|
||||
* Flag for {@link #performShortcut(int, KeyEvent, int)}: if set, always
|
||||
* close the menu after executing the shortcut. Closing the menu also resets
|
||||
* the prepared state.
|
||||
*/
|
||||
static final int FLAG_ALWAYS_PERFORM_CLOSE = 0x0002;
|
||||
|
||||
/**
|
||||
* Add a new item to the menu. This item displays the given title for its
|
||||
* label.
|
||||
*
|
||||
* @param title The text to display for the item.
|
||||
* @return The newly added menu item.
|
||||
*/
|
||||
public MenuItem add(CharSequence title);
|
||||
|
||||
/**
|
||||
* Add a new item to the menu. This item displays the given title for its
|
||||
* label.
|
||||
*
|
||||
* @param titleRes Resource identifier of title string.
|
||||
* @return The newly added menu item.
|
||||
*/
|
||||
public MenuItem add(int titleRes);
|
||||
|
||||
/**
|
||||
* Add a new item to the menu. This item displays the given title for its
|
||||
* label.
|
||||
*
|
||||
* @param groupId The group identifier that this item should be part of.
|
||||
* This can be used to define groups of items for batch state
|
||||
* changes. Normally use {@link #NONE} if an item should not be in a
|
||||
* group.
|
||||
* @param itemId Unique item ID. Use {@link #NONE} if you do not need a
|
||||
* unique ID.
|
||||
* @param order The order for the item. Use {@link #NONE} if you do not care
|
||||
* about the order. See {@link MenuItem#getOrder()}.
|
||||
* @param title The text to display for the item.
|
||||
* @return The newly added menu item.
|
||||
*/
|
||||
public MenuItem add(int groupId, int itemId, int order, CharSequence title);
|
||||
|
||||
/**
|
||||
* Variation on {@link #add(int, int, int, CharSequence)} that takes a
|
||||
* string resource identifier instead of the string itself.
|
||||
*
|
||||
* @param groupId The group identifier that this item should be part of.
|
||||
* This can also be used to define groups of items for batch state
|
||||
* changes. Normally use {@link #NONE} if an item should not be in a
|
||||
* group.
|
||||
* @param itemId Unique item ID. Use {@link #NONE} if you do not need a
|
||||
* unique ID.
|
||||
* @param order The order for the item. Use {@link #NONE} if you do not care
|
||||
* about the order. See {@link MenuItem#getOrder()}.
|
||||
* @param titleRes Resource identifier of title string.
|
||||
* @return The newly added menu item.
|
||||
*/
|
||||
public MenuItem add(int groupId, int itemId, int order, int titleRes);
|
||||
|
||||
/**
|
||||
* Add a new sub-menu to the menu. This item displays the given title for
|
||||
* its label. To modify other attributes on the submenu's menu item, use
|
||||
* {@link SubMenu#getItem()}.
|
||||
*
|
||||
* @param title The text to display for the item.
|
||||
* @return The newly added sub-menu
|
||||
*/
|
||||
SubMenu addSubMenu(final CharSequence title);
|
||||
|
||||
/**
|
||||
* Add a new sub-menu to the menu. This item displays the given title for
|
||||
* its label. To modify other attributes on the submenu's menu item, use
|
||||
* {@link SubMenu#getItem()}.
|
||||
*
|
||||
* @param titleRes Resource identifier of title string.
|
||||
* @return The newly added sub-menu
|
||||
*/
|
||||
SubMenu addSubMenu(final int titleRes);
|
||||
|
||||
/**
|
||||
* Add a new sub-menu to the menu. This item displays the given
|
||||
* <var>title</var> for its label. To modify other attributes on the
|
||||
* submenu's menu item, use {@link SubMenu#getItem()}.
|
||||
*<p>
|
||||
* Note that you can only have one level of sub-menus, i.e. you cannnot add
|
||||
* a subMenu to a subMenu: An {@link UnsupportedOperationException} will be
|
||||
* thrown if you try.
|
||||
*
|
||||
* @param groupId The group identifier that this item should be part of.
|
||||
* This can also be used to define groups of items for batch state
|
||||
* changes. Normally use {@link #NONE} if an item should not be in a
|
||||
* group.
|
||||
* @param itemId Unique item ID. Use {@link #NONE} if you do not need a
|
||||
* unique ID.
|
||||
* @param order The order for the item. Use {@link #NONE} if you do not care
|
||||
* about the order. See {@link MenuItem#getOrder()}.
|
||||
* @param title The text to display for the item.
|
||||
* @return The newly added sub-menu
|
||||
*/
|
||||
SubMenu addSubMenu(final int groupId, final int itemId, int order, final CharSequence title);
|
||||
|
||||
/**
|
||||
* Variation on {@link #addSubMenu(int, int, int, CharSequence)} that takes
|
||||
* a string resource identifier for the title instead of the string itself.
|
||||
*
|
||||
* @param groupId The group identifier that this item should be part of.
|
||||
* This can also be used to define groups of items for batch state
|
||||
* changes. Normally use {@link #NONE} if an item should not be in a group.
|
||||
* @param itemId Unique item ID. Use {@link #NONE} if you do not need a unique ID.
|
||||
* @param order The order for the item. Use {@link #NONE} if you do not care about the
|
||||
* order. See {@link MenuItem#getOrder()}.
|
||||
* @param titleRes Resource identifier of title string.
|
||||
* @return The newly added sub-menu
|
||||
*/
|
||||
SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes);
|
||||
|
||||
/**
|
||||
* Add a group of menu items corresponding to actions that can be performed
|
||||
* for a particular Intent. The Intent is most often configured with a null
|
||||
* action, the data that the current activity is working with, and includes
|
||||
* either the {@link Intent#CATEGORY_ALTERNATIVE} or
|
||||
* {@link Intent#CATEGORY_SELECTED_ALTERNATIVE} to find activities that have
|
||||
* said they would like to be included as optional action. You can, however,
|
||||
* use any Intent you want.
|
||||
*
|
||||
* <p>
|
||||
* See {@link android.content.pm.PackageManager#queryIntentActivityOptions}
|
||||
* for more * details on the <var>caller</var>, <var>specifics</var>, and
|
||||
* <var>intent</var> arguments. The list returned by that function is used
|
||||
* to populate the resulting menu items.
|
||||
*
|
||||
* <p>
|
||||
* All of the menu items of possible options for the intent will be added
|
||||
* with the given group and id. You can use the group to control ordering of
|
||||
* the items in relation to other items in the menu. Normally this function
|
||||
* will automatically remove any existing items in the menu in the same
|
||||
* group and place a divider above and below the added items; this behavior
|
||||
* can be modified with the <var>flags</var> parameter. For each of the
|
||||
* generated items {@link MenuItem#setIntent} is called to associate the
|
||||
* appropriate Intent with the item; this means the activity will
|
||||
* automatically be started for you without having to do anything else.
|
||||
*
|
||||
* @param groupId The group identifier that the items should be part of.
|
||||
* This can also be used to define groups of items for batch state
|
||||
* changes. Normally use {@link #NONE} if the items should not be in
|
||||
* a group.
|
||||
* @param itemId Unique item ID. Use {@link #NONE} if you do not need a
|
||||
* unique ID.
|
||||
* @param order The order for the items. Use {@link #NONE} if you do not
|
||||
* care about the order. See {@link MenuItem#getOrder()}.
|
||||
* @param caller The current activity component name as defined by
|
||||
* queryIntentActivityOptions().
|
||||
* @param specifics Specific items to place first as defined by
|
||||
* queryIntentActivityOptions().
|
||||
* @param intent Intent describing the kinds of items to populate in the
|
||||
* list as defined by queryIntentActivityOptions().
|
||||
* @param flags Additional options controlling how the items are added.
|
||||
* @param outSpecificItems Optional array in which to place the menu items
|
||||
* that were generated for each of the <var>specifics</var> that were
|
||||
* requested. Entries may be null if no activity was found for that
|
||||
* specific action.
|
||||
* @return The number of menu items that were added.
|
||||
*
|
||||
* @see #FLAG_APPEND_TO_GROUP
|
||||
* @see MenuItem#setIntent
|
||||
* @see android.content.pm.PackageManager#queryIntentActivityOptions
|
||||
*/
|
||||
public int addIntentOptions(int groupId, int itemId, int order,
|
||||
ComponentName caller, Intent[] specifics,
|
||||
Intent intent, int flags, MenuItem[] outSpecificItems);
|
||||
|
||||
/**
|
||||
* Remove the item with the given identifier.
|
||||
*
|
||||
* @param id The item to be removed. If there is no item with this
|
||||
* identifier, nothing happens.
|
||||
*/
|
||||
public void removeItem(int id);
|
||||
|
||||
/**
|
||||
* Remove all items in the given group.
|
||||
*
|
||||
* @param groupId The group to be removed. If there are no items in this
|
||||
* group, nothing happens.
|
||||
*/
|
||||
public void removeGroup(int groupId);
|
||||
|
||||
/**
|
||||
* Remove all existing items from the menu, leaving it empty as if it had
|
||||
* just been created.
|
||||
*/
|
||||
public void clear();
|
||||
|
||||
/**
|
||||
* Control whether a particular group of items can show a check mark. This
|
||||
* is similar to calling {@link MenuItem#setCheckable} on all of the menu items
|
||||
* with the given group identifier, but in addition you can control whether
|
||||
* this group contains a mutually-exclusive set items. This should be called
|
||||
* after the items of the group have been added to the menu.
|
||||
*
|
||||
* @param group The group of items to operate on.
|
||||
* @param checkable Set to true to allow a check mark, false to
|
||||
* disallow. The default is false.
|
||||
* @param exclusive If set to true, only one item in this group can be
|
||||
* checked at a time; checking an item will automatically
|
||||
* uncheck all others in the group. If set to false, each
|
||||
* item can be checked independently of the others.
|
||||
*
|
||||
* @see MenuItem#setCheckable
|
||||
* @see MenuItem#setChecked
|
||||
*/
|
||||
public void setGroupCheckable(int group, boolean checkable, boolean exclusive);
|
||||
|
||||
/**
|
||||
* Show or hide all menu items that are in the given group.
|
||||
*
|
||||
* @param group The group of items to operate on.
|
||||
* @param visible If true the items are visible, else they are hidden.
|
||||
*
|
||||
* @see MenuItem#setVisible
|
||||
*/
|
||||
public void setGroupVisible(int group, boolean visible);
|
||||
|
||||
/**
|
||||
* Enable or disable all menu items that are in the given group.
|
||||
*
|
||||
* @param group The group of items to operate on.
|
||||
* @param enabled If true the items will be enabled, else they will be disabled.
|
||||
*
|
||||
* @see MenuItem#setEnabled
|
||||
*/
|
||||
public void setGroupEnabled(int group, boolean enabled);
|
||||
|
||||
/**
|
||||
* Return whether the menu currently has item items that are visible.
|
||||
*
|
||||
* @return True if there is one or more item visible,
|
||||
* else false.
|
||||
*/
|
||||
public boolean hasVisibleItems();
|
||||
|
||||
/**
|
||||
* Return the menu item with a particular identifier.
|
||||
*
|
||||
* @param id The identifier to find.
|
||||
*
|
||||
* @return The menu item object, or null if there is no item with
|
||||
* this identifier.
|
||||
*/
|
||||
public MenuItem findItem(int id);
|
||||
|
||||
/**
|
||||
* Get the number of items in the menu. Note that this will change any
|
||||
* times items are added or removed from the menu.
|
||||
*
|
||||
* @return The item count.
|
||||
*/
|
||||
public int size();
|
||||
|
||||
/**
|
||||
* Gets the menu item at the given index.
|
||||
*
|
||||
* @param index The index of the menu item to return.
|
||||
* @return The menu item.
|
||||
* @exception IndexOutOfBoundsException
|
||||
* when {@code index < 0 || >= size()}
|
||||
*/
|
||||
public MenuItem getItem(int index);
|
||||
|
||||
/**
|
||||
* Closes the menu, if open.
|
||||
*/
|
||||
public void close();
|
||||
|
||||
/**
|
||||
* Execute the menu item action associated with the given shortcut
|
||||
* character.
|
||||
*
|
||||
* @param keyCode The keycode of the shortcut key.
|
||||
* @param event Key event message.
|
||||
* @param flags Additional option flags or 0.
|
||||
*
|
||||
* @return If the given shortcut exists and is shown, returns
|
||||
* true; else returns false.
|
||||
*
|
||||
* @see #FLAG_PERFORM_NO_CLOSE
|
||||
*/
|
||||
public boolean performShortcut(int keyCode, KeyEvent event, int flags);
|
||||
|
||||
/**
|
||||
* Is a keypress one of the defined shortcut keys for this window.
|
||||
* @param keyCode the key code from {@link KeyEvent} to check.
|
||||
* @param event the {@link KeyEvent} to use to help check.
|
||||
*/
|
||||
boolean isShortcutKey(int keyCode, KeyEvent event);
|
||||
|
||||
/**
|
||||
* Execute the menu item action associated with the given menu identifier.
|
||||
*
|
||||
* @param id Identifier associated with the menu item.
|
||||
* @param flags Additional option flags or 0.
|
||||
*
|
||||
* @return If the given identifier exists and is shown, returns
|
||||
* true; else returns false.
|
||||
*
|
||||
* @see #FLAG_PERFORM_NO_CLOSE
|
||||
*/
|
||||
public boolean performIdentifierAction(int id, int flags);
|
||||
|
||||
|
||||
/**
|
||||
* Control whether the menu should be running in qwerty mode (alphabetic
|
||||
* shortcuts) or 12-key mode (numeric shortcuts).
|
||||
*
|
||||
* @param isQwerty If true the menu will use alphabetic shortcuts; else it
|
||||
* will use numeric shortcuts.
|
||||
*/
|
||||
public void setQwertyMode(boolean isQwerty);
|
||||
}
|
|
@ -1,495 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
* 2011 Jake Wharton
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.view;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Constructor;
|
||||
import java.lang.reflect.Method;
|
||||
import org.xmlpull.v1.XmlPullParser;
|
||||
import org.xmlpull.v1.XmlPullParserException;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.content.res.XmlResourceParser;
|
||||
import android.util.AttributeSet;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.util.Xml;
|
||||
import android.view.InflateException;
|
||||
import android.view.View;
|
||||
|
||||
import com.actionbarsherlock.R;
|
||||
import com.actionbarsherlock.internal.view.menu.MenuItemImpl;
|
||||
|
||||
/**
|
||||
* This class is used to instantiate menu XML files into Menu objects.
|
||||
* <p>
|
||||
* For performance reasons, menu inflation relies heavily on pre-processing of
|
||||
* XML files that is done at build time. Therefore, it is not currently possible
|
||||
* to use MenuInflater with an XmlPullParser over a plain XML file at runtime;
|
||||
* it only works with an XmlPullParser returned from a compiled resource (R.
|
||||
* <em>something</em> file.)
|
||||
*/
|
||||
public class MenuInflater {
|
||||
private static final String LOG_TAG = "MenuInflater";
|
||||
|
||||
/** Menu tag name in XML. */
|
||||
private static final String XML_MENU = "menu";
|
||||
|
||||
/** Group tag name in XML. */
|
||||
private static final String XML_GROUP = "group";
|
||||
|
||||
/** Item tag name in XML. */
|
||||
private static final String XML_ITEM = "item";
|
||||
|
||||
private static final int NO_ID = 0;
|
||||
|
||||
private static final Class<?>[] ACTION_VIEW_CONSTRUCTOR_SIGNATURE = new Class[] {Context.class};
|
||||
|
||||
private static final Class<?>[] ACTION_PROVIDER_CONSTRUCTOR_SIGNATURE = ACTION_VIEW_CONSTRUCTOR_SIGNATURE;
|
||||
|
||||
private final Object[] mActionViewConstructorArguments;
|
||||
|
||||
private final Object[] mActionProviderConstructorArguments;
|
||||
|
||||
private Context mContext;
|
||||
private Object mRealOwner;
|
||||
|
||||
/**
|
||||
* Constructs a menu inflater.
|
||||
*
|
||||
* @see Activity#getMenuInflater()
|
||||
*/
|
||||
public MenuInflater(Context context) {
|
||||
mContext = context;
|
||||
mRealOwner = context;
|
||||
mActionViewConstructorArguments = new Object[] {context};
|
||||
mActionProviderConstructorArguments = mActionViewConstructorArguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a menu inflater.
|
||||
*
|
||||
* @see Activity#getMenuInflater()
|
||||
* @hide
|
||||
*/
|
||||
public MenuInflater(Context context, Object realOwner) {
|
||||
mContext = context;
|
||||
mRealOwner = realOwner;
|
||||
mActionViewConstructorArguments = new Object[] {context};
|
||||
mActionProviderConstructorArguments = mActionViewConstructorArguments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inflate a menu hierarchy from the specified XML resource. Throws
|
||||
* {@link InflateException} if there is an error.
|
||||
*
|
||||
* @param menuRes Resource ID for an XML layout resource to load (e.g.,
|
||||
* <code>R.menu.main_activity</code>)
|
||||
* @param menu The Menu to inflate into. The items and submenus will be
|
||||
* added to this Menu.
|
||||
*/
|
||||
public void inflate(int menuRes, Menu menu) {
|
||||
XmlResourceParser parser = null;
|
||||
try {
|
||||
parser = mContext.getResources().getLayout(menuRes);
|
||||
AttributeSet attrs = Xml.asAttributeSet(parser);
|
||||
|
||||
parseMenu(parser, attrs, menu);
|
||||
} catch (XmlPullParserException e) {
|
||||
throw new InflateException("Error inflating menu XML", e);
|
||||
} catch (IOException e) {
|
||||
throw new InflateException("Error inflating menu XML", e);
|
||||
} finally {
|
||||
if (parser != null) parser.close();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called internally to fill the given menu. If a sub menu is seen, it will
|
||||
* call this recursively.
|
||||
*/
|
||||
private void parseMenu(XmlPullParser parser, AttributeSet attrs, Menu menu)
|
||||
throws XmlPullParserException, IOException {
|
||||
MenuState menuState = new MenuState(menu);
|
||||
|
||||
int eventType = parser.getEventType();
|
||||
String tagName;
|
||||
boolean lookingForEndOfUnknownTag = false;
|
||||
String unknownTagName = null;
|
||||
|
||||
// This loop will skip to the menu start tag
|
||||
do {
|
||||
if (eventType == XmlPullParser.START_TAG) {
|
||||
tagName = parser.getName();
|
||||
if (tagName.equals(XML_MENU)) {
|
||||
// Go to next tag
|
||||
eventType = parser.next();
|
||||
break;
|
||||
}
|
||||
|
||||
throw new RuntimeException("Expecting menu, got " + tagName);
|
||||
}
|
||||
eventType = parser.next();
|
||||
} while (eventType != XmlPullParser.END_DOCUMENT);
|
||||
|
||||
boolean reachedEndOfMenu = false;
|
||||
while (!reachedEndOfMenu) {
|
||||
switch (eventType) {
|
||||
case XmlPullParser.START_TAG:
|
||||
if (lookingForEndOfUnknownTag) {
|
||||
break;
|
||||
}
|
||||
|
||||
tagName = parser.getName();
|
||||
if (tagName.equals(XML_GROUP)) {
|
||||
menuState.readGroup(attrs);
|
||||
} else if (tagName.equals(XML_ITEM)) {
|
||||
menuState.readItem(attrs);
|
||||
} else if (tagName.equals(XML_MENU)) {
|
||||
// A menu start tag denotes a submenu for an item
|
||||
SubMenu subMenu = menuState.addSubMenuItem();
|
||||
|
||||
// Parse the submenu into returned SubMenu
|
||||
parseMenu(parser, attrs, subMenu);
|
||||
} else {
|
||||
lookingForEndOfUnknownTag = true;
|
||||
unknownTagName = tagName;
|
||||
}
|
||||
break;
|
||||
|
||||
case XmlPullParser.END_TAG:
|
||||
tagName = parser.getName();
|
||||
if (lookingForEndOfUnknownTag && tagName.equals(unknownTagName)) {
|
||||
lookingForEndOfUnknownTag = false;
|
||||
unknownTagName = null;
|
||||
} else if (tagName.equals(XML_GROUP)) {
|
||||
menuState.resetGroup();
|
||||
} else if (tagName.equals(XML_ITEM)) {
|
||||
// Add the item if it hasn't been added (if the item was
|
||||
// a submenu, it would have been added already)
|
||||
if (!menuState.hasAddedItem()) {
|
||||
if (menuState.itemActionProvider != null &&
|
||||
menuState.itemActionProvider.hasSubMenu()) {
|
||||
menuState.addSubMenuItem();
|
||||
} else {
|
||||
menuState.addItem();
|
||||
}
|
||||
}
|
||||
} else if (tagName.equals(XML_MENU)) {
|
||||
reachedEndOfMenu = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case XmlPullParser.END_DOCUMENT:
|
||||
throw new RuntimeException("Unexpected end of document");
|
||||
}
|
||||
|
||||
eventType = parser.next();
|
||||
}
|
||||
}
|
||||
|
||||
private static class InflatedOnMenuItemClickListener
|
||||
implements MenuItem.OnMenuItemClickListener {
|
||||
private static final Class<?>[] PARAM_TYPES = new Class[] { MenuItem.class };
|
||||
|
||||
private Object mRealOwner;
|
||||
private Method mMethod;
|
||||
|
||||
public InflatedOnMenuItemClickListener(Object realOwner, String methodName) {
|
||||
mRealOwner = realOwner;
|
||||
Class<?> c = realOwner.getClass();
|
||||
try {
|
||||
mMethod = c.getMethod(methodName, PARAM_TYPES);
|
||||
} catch (Exception e) {
|
||||
InflateException ex = new InflateException(
|
||||
"Couldn't resolve menu item onClick handler " + methodName +
|
||||
" in class " + c.getName());
|
||||
ex.initCause(e);
|
||||
throw ex;
|
||||
}
|
||||
}
|
||||
|
||||
public boolean onMenuItemClick(MenuItem item) {
|
||||
try {
|
||||
if (mMethod.getReturnType() == Boolean.TYPE) {
|
||||
return (Boolean) mMethod.invoke(mRealOwner, item);
|
||||
} else {
|
||||
mMethod.invoke(mRealOwner, item);
|
||||
return true;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* State for the current menu.
|
||||
* <p>
|
||||
* Groups can not be nested unless there is another menu (which will have
|
||||
* its state class).
|
||||
*/
|
||||
private class MenuState {
|
||||
private Menu menu;
|
||||
|
||||
/*
|
||||
* Group state is set on items as they are added, allowing an item to
|
||||
* override its group state. (As opposed to set on items at the group end tag.)
|
||||
*/
|
||||
private int groupId;
|
||||
private int groupCategory;
|
||||
private int groupOrder;
|
||||
private int groupCheckable;
|
||||
private boolean groupVisible;
|
||||
private boolean groupEnabled;
|
||||
|
||||
private boolean itemAdded;
|
||||
private int itemId;
|
||||
private int itemCategoryOrder;
|
||||
private CharSequence itemTitle;
|
||||
private CharSequence itemTitleCondensed;
|
||||
private int itemIconResId;
|
||||
private char itemAlphabeticShortcut;
|
||||
private char itemNumericShortcut;
|
||||
/**
|
||||
* Sync to attrs.xml enum:
|
||||
* - 0: none
|
||||
* - 1: all
|
||||
* - 2: exclusive
|
||||
*/
|
||||
private int itemCheckable;
|
||||
private boolean itemChecked;
|
||||
private boolean itemVisible;
|
||||
private boolean itemEnabled;
|
||||
|
||||
/**
|
||||
* Sync to attrs.xml enum, values in MenuItem:
|
||||
* - 0: never
|
||||
* - 1: ifRoom
|
||||
* - 2: always
|
||||
* - -1: Safe sentinel for "no value".
|
||||
*/
|
||||
private int itemShowAsAction;
|
||||
|
||||
private int itemActionViewLayout;
|
||||
private String itemActionViewClassName;
|
||||
private String itemActionProviderClassName;
|
||||
|
||||
private String itemListenerMethodName;
|
||||
|
||||
private ActionProvider itemActionProvider;
|
||||
|
||||
private static final int defaultGroupId = NO_ID;
|
||||
private static final int defaultItemId = NO_ID;
|
||||
private static final int defaultItemCategory = 0;
|
||||
private static final int defaultItemOrder = 0;
|
||||
private static final int defaultItemCheckable = 0;
|
||||
private static final boolean defaultItemChecked = false;
|
||||
private static final boolean defaultItemVisible = true;
|
||||
private static final boolean defaultItemEnabled = true;
|
||||
|
||||
public MenuState(final Menu menu) {
|
||||
this.menu = menu;
|
||||
|
||||
resetGroup();
|
||||
}
|
||||
|
||||
public void resetGroup() {
|
||||
groupId = defaultGroupId;
|
||||
groupCategory = defaultItemCategory;
|
||||
groupOrder = defaultItemOrder;
|
||||
groupCheckable = defaultItemCheckable;
|
||||
groupVisible = defaultItemVisible;
|
||||
groupEnabled = defaultItemEnabled;
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the parser is pointing to a group tag.
|
||||
*/
|
||||
public void readGroup(AttributeSet attrs) {
|
||||
TypedArray a = mContext.obtainStyledAttributes(attrs,
|
||||
R.styleable.SherlockMenuGroup);
|
||||
|
||||
groupId = a.getResourceId(R.styleable.SherlockMenuGroup_android_id, defaultGroupId);
|
||||
groupCategory = a.getInt(R.styleable.SherlockMenuGroup_android_menuCategory, defaultItemCategory);
|
||||
groupOrder = a.getInt(R.styleable.SherlockMenuGroup_android_orderInCategory, defaultItemOrder);
|
||||
groupCheckable = a.getInt(R.styleable.SherlockMenuGroup_android_checkableBehavior, defaultItemCheckable);
|
||||
groupVisible = a.getBoolean(R.styleable.SherlockMenuGroup_android_visible, defaultItemVisible);
|
||||
groupEnabled = a.getBoolean(R.styleable.SherlockMenuGroup_android_enabled, defaultItemEnabled);
|
||||
|
||||
a.recycle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when the parser is pointing to an item tag.
|
||||
*/
|
||||
public void readItem(AttributeSet attrs) {
|
||||
TypedArray a = mContext.obtainStyledAttributes(attrs,
|
||||
R.styleable.SherlockMenuItem);
|
||||
|
||||
// Inherit attributes from the group as default value
|
||||
itemId = a.getResourceId(R.styleable.SherlockMenuItem_android_id, defaultItemId);
|
||||
final int category = a.getInt(R.styleable.SherlockMenuItem_android_menuCategory, groupCategory);
|
||||
final int order = a.getInt(R.styleable.SherlockMenuItem_android_orderInCategory, groupOrder);
|
||||
itemCategoryOrder = (category & Menu.CATEGORY_MASK) | (order & Menu.USER_MASK);
|
||||
itemTitle = a.getText(R.styleable.SherlockMenuItem_android_title);
|
||||
itemTitleCondensed = a.getText(R.styleable.SherlockMenuItem_android_titleCondensed);
|
||||
itemIconResId = a.getResourceId(R.styleable.SherlockMenuItem_android_icon, 0);
|
||||
itemAlphabeticShortcut =
|
||||
getShortcut(a.getString(R.styleable.SherlockMenuItem_android_alphabeticShortcut));
|
||||
itemNumericShortcut =
|
||||
getShortcut(a.getString(R.styleable.SherlockMenuItem_android_numericShortcut));
|
||||
if (a.hasValue(R.styleable.SherlockMenuItem_android_checkable)) {
|
||||
// Item has attribute checkable, use it
|
||||
itemCheckable = a.getBoolean(R.styleable.SherlockMenuItem_android_checkable, false) ? 1 : 0;
|
||||
} else {
|
||||
// Item does not have attribute, use the group's (group can have one more state
|
||||
// for checkable that represents the exclusive checkable)
|
||||
itemCheckable = groupCheckable;
|
||||
}
|
||||
|
||||
itemChecked = a.getBoolean(R.styleable.SherlockMenuItem_android_checked, defaultItemChecked);
|
||||
itemVisible = a.getBoolean(R.styleable.SherlockMenuItem_android_visible, groupVisible);
|
||||
itemEnabled = a.getBoolean(R.styleable.SherlockMenuItem_android_enabled, groupEnabled);
|
||||
|
||||
TypedValue value = new TypedValue();
|
||||
a.getValue(R.styleable.SherlockMenuItem_android_showAsAction, value);
|
||||
itemShowAsAction = value.type == TypedValue.TYPE_INT_HEX ? value.data : -1;
|
||||
|
||||
itemListenerMethodName = a.getString(R.styleable.SherlockMenuItem_android_onClick);
|
||||
itemActionViewLayout = a.getResourceId(R.styleable.SherlockMenuItem_android_actionLayout, 0);
|
||||
|
||||
// itemActionViewClassName = a.getString(R.styleable.SherlockMenuItem_android_actionViewClass);
|
||||
value = new TypedValue();
|
||||
a.getValue(R.styleable.SherlockMenuItem_android_actionViewClass, value);
|
||||
itemActionViewClassName = value.type == TypedValue.TYPE_STRING ? value.string.toString() : null;
|
||||
|
||||
// itemActionProviderClassName = a.getString(R.styleable.SherlockMenuItem_android_actionProviderClass);
|
||||
value = new TypedValue();
|
||||
a.getValue(R.styleable.SherlockMenuItem_android_actionProviderClass, value);
|
||||
itemActionProviderClassName = value.type == TypedValue.TYPE_STRING ? value.string.toString() : null;
|
||||
|
||||
final boolean hasActionProvider = itemActionProviderClassName != null;
|
||||
if (hasActionProvider && itemActionViewLayout == 0 && itemActionViewClassName == null) {
|
||||
itemActionProvider = newInstance(itemActionProviderClassName,
|
||||
ACTION_PROVIDER_CONSTRUCTOR_SIGNATURE,
|
||||
mActionProviderConstructorArguments);
|
||||
} else {
|
||||
if (hasActionProvider) {
|
||||
Log.w(LOG_TAG, "Ignoring attribute 'actionProviderClass'."
|
||||
+ " Action view already specified.");
|
||||
}
|
||||
itemActionProvider = null;
|
||||
}
|
||||
|
||||
a.recycle();
|
||||
|
||||
itemAdded = false;
|
||||
}
|
||||
|
||||
private char getShortcut(String shortcutString) {
|
||||
if (shortcutString == null) {
|
||||
return 0;
|
||||
} else {
|
||||
return shortcutString.charAt(0);
|
||||
}
|
||||
}
|
||||
|
||||
private void setItem(MenuItem item) {
|
||||
item.setChecked(itemChecked)
|
||||
.setVisible(itemVisible)
|
||||
.setEnabled(itemEnabled)
|
||||
.setCheckable(itemCheckable >= 1)
|
||||
.setTitleCondensed(itemTitleCondensed)
|
||||
.setIcon(itemIconResId)
|
||||
.setAlphabeticShortcut(itemAlphabeticShortcut)
|
||||
.setNumericShortcut(itemNumericShortcut);
|
||||
|
||||
if (itemShowAsAction >= 0) {
|
||||
item.setShowAsAction(itemShowAsAction);
|
||||
}
|
||||
|
||||
if (itemListenerMethodName != null) {
|
||||
if (mContext.isRestricted()) {
|
||||
throw new IllegalStateException("The android:onClick attribute cannot "
|
||||
+ "be used within a restricted context");
|
||||
}
|
||||
item.setOnMenuItemClickListener(
|
||||
new InflatedOnMenuItemClickListener(mRealOwner, itemListenerMethodName));
|
||||
}
|
||||
|
||||
if (itemCheckable >= 2) {
|
||||
if (item instanceof MenuItemImpl) {
|
||||
MenuItemImpl impl = (MenuItemImpl) item;
|
||||
impl.setExclusiveCheckable(true);
|
||||
} else {
|
||||
menu.setGroupCheckable(groupId, true, true);
|
||||
}
|
||||
}
|
||||
|
||||
boolean actionViewSpecified = false;
|
||||
if (itemActionViewClassName != null) {
|
||||
View actionView = (View) newInstance(itemActionViewClassName,
|
||||
ACTION_VIEW_CONSTRUCTOR_SIGNATURE, mActionViewConstructorArguments);
|
||||
item.setActionView(actionView);
|
||||
actionViewSpecified = true;
|
||||
}
|
||||
if (itemActionViewLayout > 0) {
|
||||
if (!actionViewSpecified) {
|
||||
item.setActionView(itemActionViewLayout);
|
||||
actionViewSpecified = true;
|
||||
} else {
|
||||
Log.w(LOG_TAG, "Ignoring attribute 'itemActionViewLayout'."
|
||||
+ " Action view already specified.");
|
||||
}
|
||||
}
|
||||
if (itemActionProvider != null) {
|
||||
item.setActionProvider(itemActionProvider);
|
||||
}
|
||||
}
|
||||
|
||||
public void addItem() {
|
||||
itemAdded = true;
|
||||
setItem(menu.add(groupId, itemId, itemCategoryOrder, itemTitle));
|
||||
}
|
||||
|
||||
public SubMenu addSubMenuItem() {
|
||||
itemAdded = true;
|
||||
SubMenu subMenu = menu.addSubMenu(groupId, itemId, itemCategoryOrder, itemTitle);
|
||||
setItem(subMenu.getItem());
|
||||
return subMenu;
|
||||
}
|
||||
|
||||
public boolean hasAddedItem() {
|
||||
return itemAdded;
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T newInstance(String className, Class<?>[] constructorSignature,
|
||||
Object[] arguments) {
|
||||
try {
|
||||
Class<?> clazz = mContext.getClassLoader().loadClass(className);
|
||||
Constructor<?> constructor = clazz.getConstructor(constructorSignature);
|
||||
return (T) constructor.newInstance(arguments);
|
||||
} catch (Exception e) {
|
||||
Log.w(LOG_TAG, "Cannot instantiate class: " + className, e);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,598 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2008 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.view;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.ContextMenu.ContextMenuInfo;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Interface for direct access to a previously created menu item.
|
||||
* <p>
|
||||
* An Item is returned by calling one of the {@link android.view.Menu#add}
|
||||
* methods.
|
||||
* <p>
|
||||
* For a feature set of specific menu types, see {@link Menu}.
|
||||
*
|
||||
* <div class="special reference">
|
||||
* <h3>Developer Guides</h3>
|
||||
* <p>For information about creating menus, read the
|
||||
* <a href="{@docRoot}guide/topics/ui/menus.html">Menus</a> developer guide.</p>
|
||||
* </div>
|
||||
*/
|
||||
public interface MenuItem {
|
||||
/*
|
||||
* These should be kept in sync with attrs.xml enum constants for showAsAction
|
||||
*/
|
||||
/** Never show this item as a button in an Action Bar. */
|
||||
public static final int SHOW_AS_ACTION_NEVER = android.view.MenuItem.SHOW_AS_ACTION_NEVER;
|
||||
/** Show this item as a button in an Action Bar if the system decides there is room for it. */
|
||||
public static final int SHOW_AS_ACTION_IF_ROOM = android.view.MenuItem.SHOW_AS_ACTION_IF_ROOM;
|
||||
/**
|
||||
* Always show this item as a button in an Action Bar.
|
||||
* Use sparingly! If too many items are set to always show in the Action Bar it can
|
||||
* crowd the Action Bar and degrade the user experience on devices with smaller screens.
|
||||
* A good rule of thumb is to have no more than 2 items set to always show at a time.
|
||||
*/
|
||||
public static final int SHOW_AS_ACTION_ALWAYS = android.view.MenuItem.SHOW_AS_ACTION_ALWAYS;
|
||||
|
||||
/**
|
||||
* When this item is in the action bar, always show it with a text label even if
|
||||
* it also has an icon specified.
|
||||
*/
|
||||
public static final int SHOW_AS_ACTION_WITH_TEXT = android.view.MenuItem.SHOW_AS_ACTION_WITH_TEXT;
|
||||
|
||||
/**
|
||||
* This item's action view collapses to a normal menu item.
|
||||
* When expanded, the action view temporarily takes over
|
||||
* a larger segment of its container.
|
||||
*/
|
||||
public static final int SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW = android.view.MenuItem.SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW;
|
||||
|
||||
/**
|
||||
* Interface definition for a callback to be invoked when a menu item is
|
||||
* clicked.
|
||||
*
|
||||
* @see Activity#onContextItemSelected(MenuItem)
|
||||
* @see Activity#onOptionsItemSelected(MenuItem)
|
||||
*/
|
||||
public interface OnMenuItemClickListener {
|
||||
/**
|
||||
* Called when a menu item has been invoked. This is the first code
|
||||
* that is executed; if it returns true, no other callbacks will be
|
||||
* executed.
|
||||
*
|
||||
* @param item The menu item that was invoked.
|
||||
*
|
||||
* @return Return true to consume this click and prevent others from
|
||||
* executing.
|
||||
*/
|
||||
public boolean onMenuItemClick(MenuItem item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface definition for a callback to be invoked when a menu item
|
||||
* marked with {@link MenuItem#SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW} is
|
||||
* expanded or collapsed.
|
||||
*
|
||||
* @see MenuItem#expandActionView()
|
||||
* @see MenuItem#collapseActionView()
|
||||
* @see MenuItem#setShowAsActionFlags(int)
|
||||
*/
|
||||
public interface OnActionExpandListener {
|
||||
/**
|
||||
* Called when a menu item with {@link MenuItem#SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}
|
||||
* is expanded.
|
||||
* @param item Item that was expanded
|
||||
* @return true if the item should expand, false if expansion should be suppressed.
|
||||
*/
|
||||
public boolean onMenuItemActionExpand(MenuItem item);
|
||||
|
||||
/**
|
||||
* Called when a menu item with {@link MenuItem#SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}
|
||||
* is collapsed.
|
||||
* @param item Item that was collapsed
|
||||
* @return true if the item should collapse, false if collapsing should be suppressed.
|
||||
*/
|
||||
public boolean onMenuItemActionCollapse(MenuItem item);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the identifier for this menu item. The identifier can not
|
||||
* be changed after the menu is created.
|
||||
*
|
||||
* @return The menu item's identifier.
|
||||
*/
|
||||
public int getItemId();
|
||||
|
||||
/**
|
||||
* Return the group identifier that this menu item is part of. The group
|
||||
* identifier can not be changed after the menu is created.
|
||||
*
|
||||
* @return The menu item's group identifier.
|
||||
*/
|
||||
public int getGroupId();
|
||||
|
||||
/**
|
||||
* Return the category and order within the category of this item. This
|
||||
* item will be shown before all items (within its category) that have
|
||||
* order greater than this value.
|
||||
* <p>
|
||||
* An order integer contains the item's category (the upper bits of the
|
||||
* integer; set by or/add the category with the order within the
|
||||
* category) and the ordering of the item within that category (the
|
||||
* lower bits). Example categories are {@link Menu#CATEGORY_SYSTEM},
|
||||
* {@link Menu#CATEGORY_SECONDARY}, {@link Menu#CATEGORY_ALTERNATIVE},
|
||||
* {@link Menu#CATEGORY_CONTAINER}. See {@link Menu} for a full list.
|
||||
*
|
||||
* @return The order of this item.
|
||||
*/
|
||||
public int getOrder();
|
||||
|
||||
/**
|
||||
* Change the title associated with this item.
|
||||
*
|
||||
* @param title The new text to be displayed.
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setTitle(CharSequence title);
|
||||
|
||||
/**
|
||||
* Change the title associated with this item.
|
||||
* <p>
|
||||
* Some menu types do not sufficient space to show the full title, and
|
||||
* instead a condensed title is preferred. See {@link Menu} for more
|
||||
* information.
|
||||
*
|
||||
* @param title The resource id of the new text to be displayed.
|
||||
* @return This Item so additional setters can be called.
|
||||
* @see #setTitleCondensed(CharSequence)
|
||||
*/
|
||||
|
||||
public MenuItem setTitle(int title);
|
||||
|
||||
/**
|
||||
* Retrieve the current title of the item.
|
||||
*
|
||||
* @return The title.
|
||||
*/
|
||||
public CharSequence getTitle();
|
||||
|
||||
/**
|
||||
* Change the condensed title associated with this item. The condensed
|
||||
* title is used in situations where the normal title may be too long to
|
||||
* be displayed.
|
||||
*
|
||||
* @param title The new text to be displayed as the condensed title.
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setTitleCondensed(CharSequence title);
|
||||
|
||||
/**
|
||||
* Retrieve the current condensed title of the item. If a condensed
|
||||
* title was never set, it will return the normal title.
|
||||
*
|
||||
* @return The condensed title, if it exists.
|
||||
* Otherwise the normal title.
|
||||
*/
|
||||
public CharSequence getTitleCondensed();
|
||||
|
||||
/**
|
||||
* Change the icon associated with this item. This icon will not always be
|
||||
* shown, so the title should be sufficient in describing this item. See
|
||||
* {@link Menu} for the menu types that support icons.
|
||||
*
|
||||
* @param icon The new icon (as a Drawable) to be displayed.
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setIcon(Drawable icon);
|
||||
|
||||
/**
|
||||
* Change the icon associated with this item. This icon will not always be
|
||||
* shown, so the title should be sufficient in describing this item. See
|
||||
* {@link Menu} for the menu types that support icons.
|
||||
* <p>
|
||||
* This method will set the resource ID of the icon which will be used to
|
||||
* lazily get the Drawable when this item is being shown.
|
||||
*
|
||||
* @param iconRes The new icon (as a resource ID) to be displayed.
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setIcon(int iconRes);
|
||||
|
||||
/**
|
||||
* Returns the icon for this item as a Drawable (getting it from resources if it hasn't been
|
||||
* loaded before).
|
||||
*
|
||||
* @return The icon as a Drawable.
|
||||
*/
|
||||
public Drawable getIcon();
|
||||
|
||||
/**
|
||||
* Change the Intent associated with this item. By default there is no
|
||||
* Intent associated with a menu item. If you set one, and nothing
|
||||
* else handles the item, then the default behavior will be to call
|
||||
* {@link android.content.Context#startActivity} with the given Intent.
|
||||
*
|
||||
* <p>Note that setIntent() can not be used with the versions of
|
||||
* {@link Menu#add} that take a Runnable, because {@link Runnable#run}
|
||||
* does not return a value so there is no way to tell if it handled the
|
||||
* item. In this case it is assumed that the Runnable always handles
|
||||
* the item, and the intent will never be started.
|
||||
*
|
||||
* @see #getIntent
|
||||
* @param intent The Intent to associated with the item. This Intent
|
||||
* object is <em>not</em> copied, so be careful not to
|
||||
* modify it later.
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setIntent(Intent intent);
|
||||
|
||||
/**
|
||||
* Return the Intent associated with this item. This returns a
|
||||
* reference to the Intent which you can change as desired to modify
|
||||
* what the Item is holding.
|
||||
*
|
||||
* @see #setIntent
|
||||
* @return Returns the last value supplied to {@link #setIntent}, or
|
||||
* null.
|
||||
*/
|
||||
public Intent getIntent();
|
||||
|
||||
/**
|
||||
* Change both the numeric and alphabetic shortcut associated with this
|
||||
* item. Note that the shortcut will be triggered when the key that
|
||||
* generates the given character is pressed alone or along with with the alt
|
||||
* key. Also note that case is not significant and that alphabetic shortcut
|
||||
* characters will be displayed in lower case.
|
||||
* <p>
|
||||
* See {@link Menu} for the menu types that support shortcuts.
|
||||
*
|
||||
* @param numericChar The numeric shortcut key. This is the shortcut when
|
||||
* using a numeric (e.g., 12-key) keyboard.
|
||||
* @param alphaChar The alphabetic shortcut key. This is the shortcut when
|
||||
* using a keyboard with alphabetic keys.
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setShortcut(char numericChar, char alphaChar);
|
||||
|
||||
/**
|
||||
* Change the numeric shortcut associated with this item.
|
||||
* <p>
|
||||
* See {@link Menu} for the menu types that support shortcuts.
|
||||
*
|
||||
* @param numericChar The numeric shortcut key. This is the shortcut when
|
||||
* using a 12-key (numeric) keyboard.
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setNumericShortcut(char numericChar);
|
||||
|
||||
/**
|
||||
* Return the char for this menu item's numeric (12-key) shortcut.
|
||||
*
|
||||
* @return Numeric character to use as a shortcut.
|
||||
*/
|
||||
public char getNumericShortcut();
|
||||
|
||||
/**
|
||||
* Change the alphabetic shortcut associated with this item. The shortcut
|
||||
* will be triggered when the key that generates the given character is
|
||||
* pressed alone or along with with the alt key. Case is not significant and
|
||||
* shortcut characters will be displayed in lower case. Note that menu items
|
||||
* with the characters '\b' or '\n' as shortcuts will get triggered by the
|
||||
* Delete key or Carriage Return key, respectively.
|
||||
* <p>
|
||||
* See {@link Menu} for the menu types that support shortcuts.
|
||||
*
|
||||
* @param alphaChar The alphabetic shortcut key. This is the shortcut when
|
||||
* using a keyboard with alphabetic keys.
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setAlphabeticShortcut(char alphaChar);
|
||||
|
||||
/**
|
||||
* Return the char for this menu item's alphabetic shortcut.
|
||||
*
|
||||
* @return Alphabetic character to use as a shortcut.
|
||||
*/
|
||||
public char getAlphabeticShortcut();
|
||||
|
||||
/**
|
||||
* Control whether this item can display a check mark. Setting this does
|
||||
* not actually display a check mark (see {@link #setChecked} for that);
|
||||
* rather, it ensures there is room in the item in which to display a
|
||||
* check mark.
|
||||
* <p>
|
||||
* See {@link Menu} for the menu types that support check marks.
|
||||
*
|
||||
* @param checkable Set to true to allow a check mark, false to
|
||||
* disallow. The default is false.
|
||||
* @see #setChecked
|
||||
* @see #isCheckable
|
||||
* @see Menu#setGroupCheckable
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setCheckable(boolean checkable);
|
||||
|
||||
/**
|
||||
* Return whether the item can currently display a check mark.
|
||||
*
|
||||
* @return If a check mark can be displayed, returns true.
|
||||
*
|
||||
* @see #setCheckable
|
||||
*/
|
||||
public boolean isCheckable();
|
||||
|
||||
/**
|
||||
* Control whether this item is shown with a check mark. Note that you
|
||||
* must first have enabled checking with {@link #setCheckable} or else
|
||||
* the check mark will not appear. If this item is a member of a group that contains
|
||||
* mutually-exclusive items (set via {@link Menu#setGroupCheckable(int, boolean, boolean)},
|
||||
* the other items in the group will be unchecked.
|
||||
* <p>
|
||||
* See {@link Menu} for the menu types that support check marks.
|
||||
*
|
||||
* @see #setCheckable
|
||||
* @see #isChecked
|
||||
* @see Menu#setGroupCheckable
|
||||
* @param checked Set to true to display a check mark, false to hide
|
||||
* it. The default value is false.
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setChecked(boolean checked);
|
||||
|
||||
/**
|
||||
* Return whether the item is currently displaying a check mark.
|
||||
*
|
||||
* @return If a check mark is displayed, returns true.
|
||||
*
|
||||
* @see #setChecked
|
||||
*/
|
||||
public boolean isChecked();
|
||||
|
||||
/**
|
||||
* Sets the visibility of the menu item. Even if a menu item is not visible,
|
||||
* it may still be invoked via its shortcut (to completely disable an item,
|
||||
* set it to invisible and {@link #setEnabled(boolean) disabled}).
|
||||
*
|
||||
* @param visible If true then the item will be visible; if false it is
|
||||
* hidden.
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setVisible(boolean visible);
|
||||
|
||||
/**
|
||||
* Return the visibility of the menu item.
|
||||
*
|
||||
* @return If true the item is visible; else it is hidden.
|
||||
*/
|
||||
public boolean isVisible();
|
||||
|
||||
/**
|
||||
* Sets whether the menu item is enabled. Disabling a menu item will not
|
||||
* allow it to be invoked via its shortcut. The menu item will still be
|
||||
* visible.
|
||||
*
|
||||
* @param enabled If true then the item will be invokable; if false it is
|
||||
* won't be invokable.
|
||||
* @return This Item so additional setters can be called.
|
||||
*/
|
||||
public MenuItem setEnabled(boolean enabled);
|
||||
|
||||
/**
|
||||
* Return the enabled state of the menu item.
|
||||
*
|
||||
* @return If true the item is enabled and hence invokable; else it is not.
|
||||
*/
|
||||
public boolean isEnabled();
|
||||
|
||||
/**
|
||||
* Check whether this item has an associated sub-menu. I.e. it is a
|
||||
* sub-menu of another menu.
|
||||
*
|
||||
* @return If true this item has a menu; else it is a
|
||||
* normal item.
|
||||
*/
|
||||
public boolean hasSubMenu();
|
||||
|
||||
/**
|
||||
* Get the sub-menu to be invoked when this item is selected, if it has
|
||||
* one. See {@link #hasSubMenu()}.
|
||||
*
|
||||
* @return The associated menu if there is one, else null
|
||||
*/
|
||||
public SubMenu getSubMenu();
|
||||
|
||||
/**
|
||||
* Set a custom listener for invocation of this menu item. In most
|
||||
* situations, it is more efficient and easier to use
|
||||
* {@link Activity#onOptionsItemSelected(MenuItem)} or
|
||||
* {@link Activity#onContextItemSelected(MenuItem)}.
|
||||
*
|
||||
* @param menuItemClickListener The object to receive invokations.
|
||||
* @return This Item so additional setters can be called.
|
||||
* @see Activity#onOptionsItemSelected(MenuItem)
|
||||
* @see Activity#onContextItemSelected(MenuItem)
|
||||
*/
|
||||
public MenuItem setOnMenuItemClickListener(MenuItem.OnMenuItemClickListener menuItemClickListener);
|
||||
|
||||
/**
|
||||
* Gets the extra information linked to this menu item. This extra
|
||||
* information is set by the View that added this menu item to the
|
||||
* menu.
|
||||
*
|
||||
* @see OnCreateContextMenuListener
|
||||
* @return The extra information linked to the View that added this
|
||||
* menu item to the menu. This can be null.
|
||||
*/
|
||||
public ContextMenuInfo getMenuInfo();
|
||||
|
||||
/**
|
||||
* Sets how this item should display in the presence of an Action Bar.
|
||||
* The parameter actionEnum is a flag set. One of {@link #SHOW_AS_ACTION_ALWAYS},
|
||||
* {@link #SHOW_AS_ACTION_IF_ROOM}, or {@link #SHOW_AS_ACTION_NEVER} should
|
||||
* be used, and you may optionally OR the value with {@link #SHOW_AS_ACTION_WITH_TEXT}.
|
||||
* SHOW_AS_ACTION_WITH_TEXT requests that when the item is shown as an action,
|
||||
* it should be shown with a text label.
|
||||
*
|
||||
* @param actionEnum How the item should display. One of
|
||||
* {@link #SHOW_AS_ACTION_ALWAYS}, {@link #SHOW_AS_ACTION_IF_ROOM}, or
|
||||
* {@link #SHOW_AS_ACTION_NEVER}. SHOW_AS_ACTION_NEVER is the default.
|
||||
*
|
||||
* @see android.app.ActionBar
|
||||
* @see #setActionView(View)
|
||||
*/
|
||||
public void setShowAsAction(int actionEnum);
|
||||
|
||||
/**
|
||||
* Sets how this item should display in the presence of an Action Bar.
|
||||
* The parameter actionEnum is a flag set. One of {@link #SHOW_AS_ACTION_ALWAYS},
|
||||
* {@link #SHOW_AS_ACTION_IF_ROOM}, or {@link #SHOW_AS_ACTION_NEVER} should
|
||||
* be used, and you may optionally OR the value with {@link #SHOW_AS_ACTION_WITH_TEXT}.
|
||||
* SHOW_AS_ACTION_WITH_TEXT requests that when the item is shown as an action,
|
||||
* it should be shown with a text label.
|
||||
*
|
||||
* <p>Note: This method differs from {@link #setShowAsAction(int)} only in that it
|
||||
* returns the current MenuItem instance for call chaining.
|
||||
*
|
||||
* @param actionEnum How the item should display. One of
|
||||
* {@link #SHOW_AS_ACTION_ALWAYS}, {@link #SHOW_AS_ACTION_IF_ROOM}, or
|
||||
* {@link #SHOW_AS_ACTION_NEVER}. SHOW_AS_ACTION_NEVER is the default.
|
||||
*
|
||||
* @see android.app.ActionBar
|
||||
* @see #setActionView(View)
|
||||
* @return This MenuItem instance for call chaining.
|
||||
*/
|
||||
public MenuItem setShowAsActionFlags(int actionEnum);
|
||||
|
||||
/**
|
||||
* Set an action view for this menu item. An action view will be displayed in place
|
||||
* of an automatically generated menu item element in the UI when this item is shown
|
||||
* as an action within a parent.
|
||||
* <p>
|
||||
* <strong>Note:</strong> Setting an action view overrides the action provider
|
||||
* set via {@link #setActionProvider(ActionProvider)}.
|
||||
* </p>
|
||||
*
|
||||
* @param view View to use for presenting this item to the user.
|
||||
* @return This Item so additional setters can be called.
|
||||
*
|
||||
* @see #setShowAsAction(int)
|
||||
*/
|
||||
public MenuItem setActionView(View view);
|
||||
|
||||
/**
|
||||
* Set an action view for this menu item. An action view will be displayed in place
|
||||
* of an automatically generated menu item element in the UI when this item is shown
|
||||
* as an action within a parent.
|
||||
* <p>
|
||||
* <strong>Note:</strong> Setting an action view overrides the action provider
|
||||
* set via {@link #setActionProvider(ActionProvider)}.
|
||||
* </p>
|
||||
*
|
||||
* @param resId Layout resource to use for presenting this item to the user.
|
||||
* @return This Item so additional setters can be called.
|
||||
*
|
||||
* @see #setShowAsAction(int)
|
||||
*/
|
||||
public MenuItem setActionView(int resId);
|
||||
|
||||
/**
|
||||
* Returns the currently set action view for this menu item.
|
||||
*
|
||||
* @return This item's action view
|
||||
*
|
||||
* @see #setActionView(View)
|
||||
* @see #setShowAsAction(int)
|
||||
*/
|
||||
public View getActionView();
|
||||
|
||||
/**
|
||||
* Sets the {@link ActionProvider} responsible for creating an action view if
|
||||
* the item is placed on the action bar. The provider also provides a default
|
||||
* action invoked if the item is placed in the overflow menu.
|
||||
* <p>
|
||||
* <strong>Note:</strong> Setting an action provider overrides the action view
|
||||
* set via {@link #setActionView(int)} or {@link #setActionView(View)}.
|
||||
* </p>
|
||||
*
|
||||
* @param actionProvider The action provider.
|
||||
* @return This Item so additional setters can be called.
|
||||
*
|
||||
* @see ActionProvider
|
||||
*/
|
||||
public MenuItem setActionProvider(ActionProvider actionProvider);
|
||||
|
||||
/**
|
||||
* Gets the {@link ActionProvider}.
|
||||
*
|
||||
* @return The action provider.
|
||||
*
|
||||
* @see ActionProvider
|
||||
* @see #setActionProvider(ActionProvider)
|
||||
*/
|
||||
public ActionProvider getActionProvider();
|
||||
|
||||
/**
|
||||
* Expand the action view associated with this menu item.
|
||||
* The menu item must have an action view set, as well as
|
||||
* the showAsAction flag {@link #SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}.
|
||||
* If a listener has been set using {@link #setOnActionExpandListener(OnActionExpandListener)}
|
||||
* it will have its {@link OnActionExpandListener#onMenuItemActionExpand(MenuItem)}
|
||||
* method invoked. The listener may return false from this method to prevent expanding
|
||||
* the action view.
|
||||
*
|
||||
* @return true if the action view was expanded, false otherwise.
|
||||
*/
|
||||
public boolean expandActionView();
|
||||
|
||||
/**
|
||||
* Collapse the action view associated with this menu item.
|
||||
* The menu item must have an action view set, as well as the showAsAction flag
|
||||
* {@link #SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}. If a listener has been set using
|
||||
* {@link #setOnActionExpandListener(OnActionExpandListener)} it will have its
|
||||
* {@link OnActionExpandListener#onMenuItemActionCollapse(MenuItem)} method invoked.
|
||||
* The listener may return false from this method to prevent collapsing the action view.
|
||||
*
|
||||
* @return true if the action view was collapsed, false otherwise.
|
||||
*/
|
||||
public boolean collapseActionView();
|
||||
|
||||
/**
|
||||
* Returns true if this menu item's action view has been expanded.
|
||||
*
|
||||
* @return true if the item's action view is expanded, false otherwise.
|
||||
*
|
||||
* @see #expandActionView()
|
||||
* @see #collapseActionView()
|
||||
* @see #SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW
|
||||
* @see OnActionExpandListener
|
||||
*/
|
||||
public boolean isActionViewExpanded();
|
||||
|
||||
/**
|
||||
* Set an {@link OnActionExpandListener} on this menu item to be notified when
|
||||
* the associated action view is expanded or collapsed. The menu item must
|
||||
* be configured to expand or collapse its action view using the flag
|
||||
* {@link #SHOW_AS_ACTION_COLLAPSE_ACTION_VIEW}.
|
||||
*
|
||||
* @param listener Listener that will respond to expand/collapse events
|
||||
* @return This menu item instance for call chaining
|
||||
*/
|
||||
public MenuItem setOnActionExpandListener(OnActionExpandListener listener);
|
||||
}
|
|
@ -1,110 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2007 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.view;
|
||||
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.view.View;
|
||||
|
||||
/**
|
||||
* Subclass of {@link Menu} for sub menus.
|
||||
* <p>
|
||||
* Sub menus do not support item icons, or nested sub menus.
|
||||
*
|
||||
* <div class="special reference">
|
||||
* <h3>Developer Guides</h3>
|
||||
* <p>For information about creating menus, read the
|
||||
* <a href="{@docRoot}guide/topics/ui/menus.html">Menus</a> developer guide.</p>
|
||||
* </div>
|
||||
*/
|
||||
|
||||
public interface SubMenu extends Menu {
|
||||
/**
|
||||
* Sets the submenu header's title to the title given in <var>titleRes</var>
|
||||
* resource identifier.
|
||||
*
|
||||
* @param titleRes The string resource identifier used for the title.
|
||||
* @return This SubMenu so additional setters can be called.
|
||||
*/
|
||||
public SubMenu setHeaderTitle(int titleRes);
|
||||
|
||||
/**
|
||||
* Sets the submenu header's title to the title given in <var>title</var>.
|
||||
*
|
||||
* @param title The character sequence used for the title.
|
||||
* @return This SubMenu so additional setters can be called.
|
||||
*/
|
||||
public SubMenu setHeaderTitle(CharSequence title);
|
||||
|
||||
/**
|
||||
* Sets the submenu header's icon to the icon given in <var>iconRes</var>
|
||||
* resource id.
|
||||
*
|
||||
* @param iconRes The resource identifier used for the icon.
|
||||
* @return This SubMenu so additional setters can be called.
|
||||
*/
|
||||
public SubMenu setHeaderIcon(int iconRes);
|
||||
|
||||
/**
|
||||
* Sets the submenu header's icon to the icon given in <var>icon</var>
|
||||
* {@link Drawable}.
|
||||
*
|
||||
* @param icon The {@link Drawable} used for the icon.
|
||||
* @return This SubMenu so additional setters can be called.
|
||||
*/
|
||||
public SubMenu setHeaderIcon(Drawable icon);
|
||||
|
||||
/**
|
||||
* Sets the header of the submenu to the {@link View} given in
|
||||
* <var>view</var>. This replaces the header title and icon (and those
|
||||
* replace this).
|
||||
*
|
||||
* @param view The {@link View} used for the header.
|
||||
* @return This SubMenu so additional setters can be called.
|
||||
*/
|
||||
public SubMenu setHeaderView(View view);
|
||||
|
||||
/**
|
||||
* Clears the header of the submenu.
|
||||
*/
|
||||
public void clearHeader();
|
||||
|
||||
/**
|
||||
* Change the icon associated with this submenu's item in its parent menu.
|
||||
*
|
||||
* @see MenuItem#setIcon(int)
|
||||
* @param iconRes The new icon (as a resource ID) to be displayed.
|
||||
* @return This SubMenu so additional setters can be called.
|
||||
*/
|
||||
public SubMenu setIcon(int iconRes);
|
||||
|
||||
/**
|
||||
* Change the icon associated with this submenu's item in its parent menu.
|
||||
*
|
||||
* @see MenuItem#setIcon(Drawable)
|
||||
* @param icon The new icon (as a Drawable) to be displayed.
|
||||
* @return This SubMenu so additional setters can be called.
|
||||
*/
|
||||
public SubMenu setIcon(Drawable icon);
|
||||
|
||||
/**
|
||||
* Gets the {@link MenuItem} that represents this submenu in the parent
|
||||
* menu. Use this for setting additional item attributes.
|
||||
*
|
||||
* @return The {@link MenuItem} that launches the submenu when invoked.
|
||||
*/
|
||||
public MenuItem getItem();
|
||||
}
|
|
@ -1,65 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2006 The Android Open Source Project
|
||||
* Copyright (C) 2011 Jake Wharton
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.view;
|
||||
|
||||
import android.content.Context;
|
||||
|
||||
/**
|
||||
* <p>Abstract base class for a top-level window look and behavior policy. An
|
||||
* instance of this class should be used as the top-level view added to the
|
||||
* window manager. It provides standard UI policies such as a background, title
|
||||
* area, default key processing, etc.</p>
|
||||
*
|
||||
* <p>The only existing implementation of this abstract class is
|
||||
* android.policy.PhoneWindow, which you should instantiate when needing a
|
||||
* Window. Eventually that class will be refactored and a factory method added
|
||||
* for creating Window instances without knowing about a particular
|
||||
* implementation.</p>
|
||||
*/
|
||||
public abstract class Window extends android.view.Window {
|
||||
public static final long FEATURE_ACTION_BAR = android.view.Window.FEATURE_ACTION_BAR;
|
||||
public static final long FEATURE_ACTION_BAR_OVERLAY = android.view.Window.FEATURE_ACTION_BAR_OVERLAY;
|
||||
public static final long FEATURE_ACTION_MODE_OVERLAY = android.view.Window.FEATURE_ACTION_MODE_OVERLAY;
|
||||
public static final long FEATURE_NO_TITLE = android.view.Window.FEATURE_NO_TITLE;
|
||||
public static final long FEATURE_PROGRESS = android.view.Window.FEATURE_PROGRESS;
|
||||
public static final long FEATURE_INDETERMINATE_PROGRESS = android.view.Window.FEATURE_INDETERMINATE_PROGRESS;
|
||||
|
||||
/**
|
||||
* Create a new instance for a context.
|
||||
*
|
||||
* @param context Context.
|
||||
*/
|
||||
private Window(Context context) {
|
||||
super(context);
|
||||
}
|
||||
|
||||
|
||||
public interface Callback {
|
||||
/**
|
||||
* Called when a panel's menu item has been selected by the user.
|
||||
*
|
||||
* @param featureId The panel that the menu is in.
|
||||
* @param item The menu item that was selected.
|
||||
*
|
||||
* @return boolean Return true to finish processing of selection, or
|
||||
* false to perform the normal menu handling (calling its
|
||||
* Runnable or sending a Message to its target Handler).
|
||||
*/
|
||||
public boolean onMenuItemSelected(int featureId, MenuItem item);
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,839 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package 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) {
|
||||
try {
|
||||
dataModel.registerObserver(mModelDataSetOberver);
|
||||
} catch (IllegalStateException e) {
|
||||
// Related to #557.
|
||||
}
|
||||
}
|
||||
mIsAttachedToWindow = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onDetachedFromWindow() {
|
||||
super.onDetachedFromWindow();
|
||||
ActivityChooserModel dataModel = mAdapter.getDataModel();
|
||||
if (dataModel != null) {
|
||||
try {
|
||||
dataModel.unregisterObserver(mModelDataSetOberver);
|
||||
} catch (IllegalStateException e) {
|
||||
//Oh, well... fixes issue #557
|
||||
}
|
||||
}
|
||||
ViewTreeObserver viewTreeObserver = getViewTreeObserver();
|
||||
if (viewTreeObserver.isAlive()) {
|
||||
viewTreeObserver.removeGlobalOnLayoutListener(mOnGlobalLayoutListener);
|
||||
}
|
||||
mIsAttachedToWindow = false;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
|
||||
View child = mActivityChooserContent;
|
||||
// If the default action is not visible we want to be as tall as the
|
||||
// ActionBar so if this widget is used in the latter it will look as
|
||||
// a normal action button.
|
||||
if (mDefaultActivityButton.getVisibility() != VISIBLE) {
|
||||
heightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec),
|
||||
MeasureSpec.EXACTLY);
|
||||
}
|
||||
measureChild(child, widthMeasureSpec, heightMeasureSpec);
|
||||
setMeasuredDimension(child.getMeasuredWidth(), child.getMeasuredHeight());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
|
||||
mActivityChooserContent.layout(0, 0, right - left, bottom - top);
|
||||
if (getListPopupWindow().isShowing()) {
|
||||
showPopupUnchecked(mAdapter.getMaxActivityCount());
|
||||
} else {
|
||||
dismissPopup();
|
||||
}
|
||||
}
|
||||
|
||||
public ActivityChooserModel getDataModel() {
|
||||
return mAdapter.getDataModel();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a listener to receive a callback when the popup is dismissed.
|
||||
*
|
||||
* @param listener The listener to be notified.
|
||||
*/
|
||||
public void setOnDismissListener(PopupWindow.OnDismissListener listener) {
|
||||
mOnDismissListener = listener;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the initial count of items shown in the activities popup
|
||||
* i.e. the items before the popup is expanded. This is an upper
|
||||
* bound since it is not guaranteed that such number of intent
|
||||
* handlers exist.
|
||||
*
|
||||
* @param itemCount The initial popup item count.
|
||||
*/
|
||||
public void setInitialActivityCount(int itemCount) {
|
||||
mInitialActivityCount = itemCount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets a content description of the default action button. This
|
||||
* resource should be a string taking one formatting argument and
|
||||
* will be used for formatting the content description of the button
|
||||
* dynamically as the default target changes. For example, a resource
|
||||
* pointing to the string "share with %1$s" will result in a content
|
||||
* description "share with Bluetooth" for the Bluetooth activity.
|
||||
*
|
||||
* @param resourceId The resource id.
|
||||
*/
|
||||
public void setDefaultActionButtonContentDescription(int resourceId) {
|
||||
mDefaultActionButtonContentDescription = resourceId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list popup window which is lazily initialized.
|
||||
*
|
||||
* @return The popup.
|
||||
*/
|
||||
private IcsListPopupWindow getListPopupWindow() {
|
||||
if (mListPopupWindow == null) {
|
||||
mListPopupWindow = new IcsListPopupWindow(getContext());
|
||||
mListPopupWindow.setAdapter(mAdapter);
|
||||
mListPopupWindow.setAnchorView(ActivityChooserView.this);
|
||||
mListPopupWindow.setModal(true);
|
||||
mListPopupWindow.setOnItemClickListener(mCallbacks);
|
||||
mListPopupWindow.setOnDismissListener(mCallbacks);
|
||||
}
|
||||
return mListPopupWindow;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the buttons state.
|
||||
*/
|
||||
private void updateAppearance() {
|
||||
// Expand overflow button.
|
||||
if (mAdapter.getCount() > 0) {
|
||||
mExpandActivityOverflowButton.setEnabled(true);
|
||||
} else {
|
||||
mExpandActivityOverflowButton.setEnabled(false);
|
||||
}
|
||||
// Default activity button.
|
||||
final int activityCount = mAdapter.getActivityCount();
|
||||
final int historySize = mAdapter.getHistorySize();
|
||||
if (activityCount > 0 && historySize > 0) {
|
||||
mDefaultActivityButton.setVisibility(VISIBLE);
|
||||
ResolveInfo activity = mAdapter.getDefaultActivity();
|
||||
PackageManager packageManager = mContext.getPackageManager();
|
||||
mDefaultActivityButtonImage.setImageDrawable(activity.loadIcon(packageManager));
|
||||
if (mDefaultActionButtonContentDescription != 0) {
|
||||
CharSequence label = activity.loadLabel(packageManager);
|
||||
String contentDescription = mContext.getString(
|
||||
mDefaultActionButtonContentDescription, label);
|
||||
mDefaultActivityButton.setContentDescription(contentDescription);
|
||||
}
|
||||
|
||||
// Work-around for #415.
|
||||
mAdapter.setShowDefaultActivity(false, false);
|
||||
} else {
|
||||
mDefaultActivityButton.setVisibility(View.GONE);
|
||||
}
|
||||
// Activity chooser content.
|
||||
if (mDefaultActivityButton.getVisibility() == VISIBLE) {
|
||||
mActivityChooserContent.setBackgroundDrawable(mActivityChooserContentBackground);
|
||||
} else {
|
||||
mActivityChooserContent.setBackgroundDrawable(null);
|
||||
mActivityChooserContent.setPadding(0, 0, 0, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Interface implementation to avoid publishing them in the APIs.
|
||||
*/
|
||||
private class Callbacks implements AdapterView.OnItemClickListener,
|
||||
View.OnClickListener, View.OnLongClickListener, PopupWindow.OnDismissListener {
|
||||
|
||||
// AdapterView#OnItemClickListener
|
||||
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
|
||||
ActivityChooserViewAdapter adapter = (ActivityChooserViewAdapter) parent.getAdapter();
|
||||
final int itemViewType = adapter.getItemViewType(position);
|
||||
switch (itemViewType) {
|
||||
case ActivityChooserViewAdapter.ITEM_VIEW_TYPE_FOOTER: {
|
||||
showPopupUnchecked(ActivityChooserViewAdapter.MAX_ACTIVITY_COUNT_UNLIMITED);
|
||||
} break;
|
||||
case ActivityChooserViewAdapter.ITEM_VIEW_TYPE_ACTIVITY: {
|
||||
dismissPopup();
|
||||
if (mIsSelectingDefaultActivity) {
|
||||
// The item at position zero is the default already.
|
||||
if (position > 0) {
|
||||
mAdapter.getDataModel().setDefaultActivity(position);
|
||||
}
|
||||
} else {
|
||||
// If the default target is not shown in the list, the first
|
||||
// item in the model is default action => adjust index
|
||||
position = mAdapter.getShowDefaultActivity() ? position : position + 1;
|
||||
Intent launchIntent = mAdapter.getDataModel().chooseActivity(position);
|
||||
if (launchIntent != null) {
|
||||
mContext.startActivity(launchIntent);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
// View.OnClickListener
|
||||
public void onClick(View view) {
|
||||
if (view == mDefaultActivityButton) {
|
||||
dismissPopup();
|
||||
ResolveInfo defaultActivity = mAdapter.getDefaultActivity();
|
||||
final int index = mAdapter.getDataModel().getActivityIndex(defaultActivity);
|
||||
Intent launchIntent = mAdapter.getDataModel().chooseActivity(index);
|
||||
if (launchIntent != null) {
|
||||
mContext.startActivity(launchIntent);
|
||||
}
|
||||
} else if (view == mExpandActivityOverflowButton) {
|
||||
mIsSelectingDefaultActivity = false;
|
||||
showPopupUnchecked(mInitialActivityCount);
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
}
|
||||
|
||||
// OnLongClickListener#onLongClick
|
||||
@Override
|
||||
public boolean onLongClick(View view) {
|
||||
if (view == mDefaultActivityButton) {
|
||||
if (mAdapter.getCount() > 0) {
|
||||
mIsSelectingDefaultActivity = true;
|
||||
showPopupUnchecked(mInitialActivityCount);
|
||||
}
|
||||
} else {
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// PopUpWindow.OnDismissListener#onDismiss
|
||||
public void onDismiss() {
|
||||
notifyOnDismissListener();
|
||||
if (mProvider != null) {
|
||||
mProvider.subUiVisibilityChanged(false);
|
||||
}
|
||||
}
|
||||
|
||||
private void notifyOnDismissListener() {
|
||||
if (mOnDismissListener != null) {
|
||||
mOnDismissListener.onDismiss();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class SetActivated {
|
||||
public static void invoke(View view, boolean activated) {
|
||||
view.setActivated(activated);
|
||||
}
|
||||
}
|
||||
|
||||
private static final boolean IS_HONEYCOMB = Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB;
|
||||
|
||||
/**
|
||||
* Adapter for backing the list of activities shown in the popup.
|
||||
*/
|
||||
private class ActivityChooserViewAdapter extends BaseAdapter {
|
||||
|
||||
public static final int MAX_ACTIVITY_COUNT_UNLIMITED = Integer.MAX_VALUE;
|
||||
|
||||
public static final int MAX_ACTIVITY_COUNT_DEFAULT = 4;
|
||||
|
||||
private static final int ITEM_VIEW_TYPE_ACTIVITY = 0;
|
||||
|
||||
private static final int ITEM_VIEW_TYPE_FOOTER = 1;
|
||||
|
||||
private static final int ITEM_VIEW_TYPE_COUNT = 3;
|
||||
|
||||
private ActivityChooserModel mDataModel;
|
||||
|
||||
private int mMaxActivityCount = MAX_ACTIVITY_COUNT_DEFAULT;
|
||||
|
||||
// Work-around for #415.
|
||||
private boolean mShowDefaultActivity = true;
|
||||
|
||||
private boolean mHighlightDefaultActivity;
|
||||
|
||||
private boolean mShowFooterView;
|
||||
|
||||
public void setDataModel(ActivityChooserModel dataModel) {
|
||||
ActivityChooserModel oldDataModel = mAdapter.getDataModel();
|
||||
if (oldDataModel != null && isShown()) {
|
||||
try {
|
||||
oldDataModel.unregisterObserver(mModelDataSetOberver);
|
||||
} catch (IllegalStateException e) {
|
||||
//Oh, well... fixes issue #557
|
||||
}
|
||||
}
|
||||
mDataModel = dataModel;
|
||||
if (dataModel != null && isShown()) {
|
||||
try {
|
||||
dataModel.registerObserver(mModelDataSetOberver);
|
||||
} catch (IllegalStateException e) {
|
||||
// Related to #557.
|
||||
}
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load diff
|
@ -1,316 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2011 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package 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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,758 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2009 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package com.actionbarsherlock.widget;
|
||||
|
||||
import android.app.SearchManager;
|
||||
import android.app.SearchableInfo;
|
||||
import android.content.ComponentName;
|
||||
import android.content.ContentResolver;
|
||||
import android.content.Context;
|
||||
import android.content.pm.ActivityInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.content.pm.PackageManager.NameNotFoundException;
|
||||
import android.content.res.ColorStateList;
|
||||
import android.content.res.Resources;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
import android.support.v4.widget.ResourceCursorAdapter;
|
||||
import android.text.Spannable;
|
||||
import android.text.SpannableString;
|
||||
import android.text.TextUtils;
|
||||
import android.text.style.TextAppearanceSpan;
|
||||
import android.util.Log;
|
||||
import android.util.TypedValue;
|
||||
import android.view.View;
|
||||
import android.view.View.OnClickListener;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
import com.actionbarsherlock.R;
|
||||
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.util.List;
|
||||
import java.util.WeakHashMap;
|
||||
|
||||
/**
|
||||
* Provides the contents for the suggestion drop-down list.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
class SuggestionsAdapter extends ResourceCursorAdapter implements OnClickListener {
|
||||
|
||||
private static final boolean DBG = false;
|
||||
private static final String LOG_TAG = "SuggestionsAdapter";
|
||||
private static final int QUERY_LIMIT = 50;
|
||||
|
||||
static final int REFINE_NONE = 0;
|
||||
static final int REFINE_BY_ENTRY = 1;
|
||||
static final int REFINE_ALL = 2;
|
||||
|
||||
private SearchManager mSearchManager;
|
||||
private SearchableInfo mSearchable;
|
||||
private SearchView mSearchView;
|
||||
private Context mProviderContext;
|
||||
private WeakHashMap<String, Drawable.ConstantState> mOutsideDrawablesCache;
|
||||
private boolean mClosed = false;
|
||||
private int mQueryRefinement = REFINE_BY_ENTRY;
|
||||
|
||||
// URL color
|
||||
private ColorStateList mUrlColor;
|
||||
|
||||
static final int INVALID_INDEX = -1;
|
||||
|
||||
// Cached column indexes, updated when the cursor changes.
|
||||
private int mText1Col = INVALID_INDEX;
|
||||
private int mText2Col = INVALID_INDEX;
|
||||
private int mText2UrlCol = INVALID_INDEX;
|
||||
private int mIconName1Col = INVALID_INDEX;
|
||||
private int mIconName2Col = INVALID_INDEX;
|
||||
private int mFlagsCol = INVALID_INDEX;
|
||||
|
||||
// private final Runnable mStartSpinnerRunnable;
|
||||
// private final Runnable mStopSpinnerRunnable;
|
||||
|
||||
/**
|
||||
* The amount of time we delay in the filter when the user presses the delete key.
|
||||
*/
|
||||
//private static final long DELETE_KEY_POST_DELAY = 500L;
|
||||
|
||||
public SuggestionsAdapter(Context context, SearchView searchView,
|
||||
SearchableInfo searchable, WeakHashMap<String, Drawable.ConstantState> outsideDrawablesCache) {
|
||||
super(context,
|
||||
R.layout.abs__search_dropdown_item_icons_2line,
|
||||
null, // no initial cursor
|
||||
true); // auto-requery
|
||||
mSearchManager = (SearchManager) mContext.getSystemService(Context.SEARCH_SERVICE);
|
||||
mSearchable = searchable;
|
||||
mProviderContext = mContext;
|
||||
mSearchView = searchView;
|
||||
|
||||
mOutsideDrawablesCache = outsideDrawablesCache;
|
||||
|
||||
// mStartSpinnerRunnable = new Runnable() {
|
||||
// public void run() {
|
||||
// // mSearchView.setWorking(true); // TODO:
|
||||
// }
|
||||
// };
|
||||
//
|
||||
// mStopSpinnerRunnable = new Runnable() {
|
||||
// public void run() {
|
||||
// // mSearchView.setWorking(false); // TODO:
|
||||
// }
|
||||
// };
|
||||
|
||||
// delay 500ms when deleting
|
||||
// TODO getFilter().setDelayer(new Filter.Delayer() {
|
||||
//
|
||||
// private int mPreviousLength = 0;
|
||||
//
|
||||
// public long getPostingDelay(CharSequence constraint) {
|
||||
// if (constraint == null) return 0;
|
||||
//
|
||||
// long delay = constraint.length() < mPreviousLength ? DELETE_KEY_POST_DELAY : 0;
|
||||
// mPreviousLength = constraint.length();
|
||||
// return delay;
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
/**
|
||||
* Enables query refinement for all suggestions. This means that an additional icon
|
||||
* will be shown for each entry. When clicked, the suggested text on that line will be
|
||||
* copied to the query text field.
|
||||
* <p>
|
||||
*
|
||||
* @param refineWhat which queries to refine. Possible values are {@link #REFINE_NONE},
|
||||
* {@link #REFINE_BY_ENTRY}, and {@link #REFINE_ALL}.
|
||||
*/
|
||||
public void setQueryRefinement(int refineWhat) {
|
||||
mQueryRefinement = refineWhat;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current query refinement preference.
|
||||
* @return value of query refinement preference
|
||||
*/
|
||||
public int getQueryRefinement() {
|
||||
return mQueryRefinement;
|
||||
}
|
||||
|
||||
/**
|
||||
* Overridden to always return <code>false</code>, since we cannot be sure that
|
||||
* suggestion sources return stable IDs.
|
||||
*/
|
||||
@Override
|
||||
public boolean hasStableIds() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Use the search suggestions provider to obtain a live cursor. This will be called
|
||||
* in a worker thread, so it's OK if the query is slow (e.g. round trip for suggestions).
|
||||
* The results will be processed in the UI thread and changeCursor() will be called.
|
||||
*/
|
||||
@Override
|
||||
public Cursor runQueryOnBackgroundThread(CharSequence constraint) {
|
||||
if (DBG) Log.d(LOG_TAG, "runQueryOnBackgroundThread(" + constraint + ")");
|
||||
String query = (constraint == null) ? "" : constraint.toString();
|
||||
/**
|
||||
* for in app search we show the progress spinner until the cursor is returned with
|
||||
* the results.
|
||||
*/
|
||||
Cursor cursor = null;
|
||||
if (mSearchView.getVisibility() != View.VISIBLE
|
||||
|| mSearchView.getWindowVisibility() != View.VISIBLE) {
|
||||
return null;
|
||||
}
|
||||
//mSearchView.getWindow().getDecorView().post(mStartSpinnerRunnable); // TODO:
|
||||
try {
|
||||
cursor = getSuggestions(query, QUERY_LIMIT);
|
||||
// trigger fill window so the spinner stays up until the results are copied over and
|
||||
// closer to being ready
|
||||
if (cursor != null) {
|
||||
cursor.getCount();
|
||||
return cursor;
|
||||
}
|
||||
} catch (RuntimeException e) {
|
||||
Log.w(LOG_TAG, "Search suggestions query threw an exception.", e);
|
||||
}
|
||||
// If cursor is null or an exception was thrown, stop the spinner and return null.
|
||||
// changeCursor doesn't get called if cursor is null
|
||||
// mSearchView.getWindow().getDecorView().post(mStopSpinnerRunnable); // TODO:
|
||||
return null;
|
||||
}
|
||||
|
||||
public Cursor getSuggestions(String query, int limit) {
|
||||
if (mSearchable == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String authority = mSearchable.getSuggestAuthority();
|
||||
if (authority == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Uri.Builder uriBuilder = new Uri.Builder()
|
||||
.scheme(ContentResolver.SCHEME_CONTENT)
|
||||
.authority(authority)
|
||||
.query("") // TODO: Remove, workaround for a bug in Uri.writeToParcel()
|
||||
.fragment(""); // TODO: Remove, workaround for a bug in Uri.writeToParcel()
|
||||
|
||||
// if content path provided, insert it now
|
||||
final String contentPath = mSearchable.getSuggestPath();
|
||||
if (contentPath != null) {
|
||||
uriBuilder.appendEncodedPath(contentPath);
|
||||
}
|
||||
|
||||
// append standard suggestion query path
|
||||
uriBuilder.appendPath(SearchManager.SUGGEST_URI_PATH_QUERY);
|
||||
|
||||
// get the query selection, may be null
|
||||
String selection = mSearchable.getSuggestSelection();
|
||||
// inject query, either as selection args or inline
|
||||
String[] selArgs = null;
|
||||
if (selection != null) { // use selection if provided
|
||||
selArgs = new String[] { query };
|
||||
} else { // no selection, use REST pattern
|
||||
uriBuilder.appendPath(query);
|
||||
}
|
||||
|
||||
if (limit > 0) {
|
||||
uriBuilder.appendQueryParameter("limit", String.valueOf(limit));
|
||||
}
|
||||
|
||||
Uri uri = uriBuilder.build();
|
||||
|
||||
// finally, make the query
|
||||
return mContext.getContentResolver().query(uri, null, selection, selArgs, null);
|
||||
}
|
||||
|
||||
public void close() {
|
||||
if (DBG) Log.d(LOG_TAG, "close()");
|
||||
changeCursor(null);
|
||||
mClosed = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDataSetChanged() {
|
||||
if (DBG) Log.d(LOG_TAG, "notifyDataSetChanged");
|
||||
super.notifyDataSetChanged();
|
||||
|
||||
// mSearchView.onDataSetChanged(); // TODO:
|
||||
|
||||
updateSpinnerState(getCursor());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void notifyDataSetInvalidated() {
|
||||
if (DBG) Log.d(LOG_TAG, "notifyDataSetInvalidated");
|
||||
super.notifyDataSetInvalidated();
|
||||
|
||||
updateSpinnerState(getCursor());
|
||||
}
|
||||
|
||||
private void updateSpinnerState(Cursor cursor) {
|
||||
Bundle extras = cursor != null ? cursor.getExtras() : null;
|
||||
if (DBG) {
|
||||
Log.d(LOG_TAG, "updateSpinnerState - extra = "
|
||||
+ (extras != null
|
||||
? extras.getBoolean(SearchManager.CURSOR_EXTRA_KEY_IN_PROGRESS)
|
||||
: null));
|
||||
}
|
||||
// Check if the Cursor indicates that the query is not complete and show the spinner
|
||||
if (extras != null
|
||||
&& extras.getBoolean(SearchManager.CURSOR_EXTRA_KEY_IN_PROGRESS)) {
|
||||
// mSearchView.getWindow().getDecorView().post(mStartSpinnerRunnable); // TODO:
|
||||
return;
|
||||
}
|
||||
// If cursor is null or is done, stop the spinner
|
||||
// mSearchView.getWindow().getDecorView().post(mStopSpinnerRunnable); // TODO:
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache columns.
|
||||
*/
|
||||
@Override
|
||||
public void changeCursor(Cursor c) {
|
||||
if (DBG) Log.d(LOG_TAG, "changeCursor(" + c + ")");
|
||||
|
||||
if (mClosed) {
|
||||
Log.w(LOG_TAG, "Tried to change cursor after adapter was closed.");
|
||||
if (c != null) c.close();
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
super.changeCursor(c);
|
||||
|
||||
if (c != null) {
|
||||
mText1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_1);
|
||||
mText2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2);
|
||||
mText2UrlCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_TEXT_2_URL);
|
||||
mIconName1Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_1);
|
||||
mIconName2Col = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_ICON_2);
|
||||
mFlagsCol = c.getColumnIndex(SearchManager.SUGGEST_COLUMN_FLAGS);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG, "error changing cursor and caching columns", e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Tags the view with cached child view look-ups.
|
||||
*/
|
||||
@Override
|
||||
public View newView(Context context, Cursor cursor, ViewGroup parent) {
|
||||
View v = super.newView(context, cursor, parent);
|
||||
v.setTag(new ChildViewCache(v));
|
||||
return v;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache of the child views of drop-drown list items, to avoid looking up the children
|
||||
* each time the contents of a list item are changed.
|
||||
*/
|
||||
private final static class ChildViewCache {
|
||||
public final TextView mText1;
|
||||
public final TextView mText2;
|
||||
public final ImageView mIcon1;
|
||||
public final ImageView mIcon2;
|
||||
public final ImageView mIconRefine;
|
||||
|
||||
public ChildViewCache(View v) {
|
||||
mText1 = (TextView) v.findViewById(android.R.id.text1);
|
||||
mText2 = (TextView) v.findViewById(android.R.id.text2);
|
||||
mIcon1 = (ImageView) v.findViewById(android.R.id.icon1);
|
||||
mIcon2 = (ImageView) v.findViewById(android.R.id.icon2);
|
||||
mIconRefine = (ImageView) v.findViewById(R.id.edit_query);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void bindView(View view, Context context, Cursor cursor) {
|
||||
ChildViewCache views = (ChildViewCache) view.getTag();
|
||||
|
||||
int flags = 0;
|
||||
if (mFlagsCol != INVALID_INDEX) {
|
||||
flags = cursor.getInt(mFlagsCol);
|
||||
}
|
||||
if (views.mText1 != null) {
|
||||
String text1 = getStringOrNull(cursor, mText1Col);
|
||||
setViewText(views.mText1, text1);
|
||||
}
|
||||
if (views.mText2 != null) {
|
||||
// First check TEXT_2_URL
|
||||
CharSequence text2 = getStringOrNull(cursor, mText2UrlCol);
|
||||
if (text2 != null) {
|
||||
text2 = formatUrl(text2);
|
||||
} else {
|
||||
text2 = getStringOrNull(cursor, mText2Col);
|
||||
}
|
||||
|
||||
// If no second line of text is indicated, allow the first line of text
|
||||
// to be up to two lines if it wants to be.
|
||||
if (TextUtils.isEmpty(text2)) {
|
||||
if (views.mText1 != null) {
|
||||
views.mText1.setSingleLine(false);
|
||||
views.mText1.setMaxLines(2);
|
||||
}
|
||||
} else {
|
||||
if (views.mText1 != null) {
|
||||
views.mText1.setSingleLine(true);
|
||||
views.mText1.setMaxLines(1);
|
||||
}
|
||||
}
|
||||
setViewText(views.mText2, text2);
|
||||
}
|
||||
|
||||
if (views.mIcon1 != null) {
|
||||
setViewDrawable(views.mIcon1, getIcon1(cursor), View.INVISIBLE);
|
||||
}
|
||||
if (views.mIcon2 != null) {
|
||||
setViewDrawable(views.mIcon2, getIcon2(cursor), View.GONE);
|
||||
}
|
||||
if (mQueryRefinement == REFINE_ALL
|
||||
|| (mQueryRefinement == REFINE_BY_ENTRY
|
||||
&& (flags & SearchManager.FLAG_QUERY_REFINEMENT) != 0)) {
|
||||
views.mIconRefine.setVisibility(View.VISIBLE);
|
||||
views.mIconRefine.setTag(views.mText1.getText());
|
||||
views.mIconRefine.setOnClickListener(this);
|
||||
} else {
|
||||
views.mIconRefine.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
public void onClick(View v) {
|
||||
Object tag = v.getTag();
|
||||
if (tag instanceof CharSequence) {
|
||||
mSearchView.onQueryRefine((CharSequence) tag);
|
||||
}
|
||||
}
|
||||
|
||||
private CharSequence formatUrl(CharSequence url) {
|
||||
if (mUrlColor == null) {
|
||||
// Lazily get the URL color from the current theme.
|
||||
TypedValue colorValue = new TypedValue();
|
||||
mContext.getTheme().resolveAttribute(R.attr.textColorSearchUrl, colorValue, true);
|
||||
mUrlColor = mContext.getResources().getColorStateList(colorValue.resourceId);
|
||||
}
|
||||
|
||||
SpannableString text = new SpannableString(url);
|
||||
text.setSpan(new TextAppearanceSpan(null, 0, 0, mUrlColor, null),
|
||||
0, url.length(),
|
||||
Spannable.SPAN_EXCLUSIVE_EXCLUSIVE);
|
||||
return text;
|
||||
}
|
||||
|
||||
private void setViewText(TextView v, CharSequence text) {
|
||||
// Set the text even if it's null, since we need to clear any previous text.
|
||||
v.setText(text);
|
||||
|
||||
if (TextUtils.isEmpty(text)) {
|
||||
v.setVisibility(View.GONE);
|
||||
} else {
|
||||
v.setVisibility(View.VISIBLE);
|
||||
}
|
||||
}
|
||||
|
||||
private Drawable getIcon1(Cursor cursor) {
|
||||
if (mIconName1Col == INVALID_INDEX) {
|
||||
return null;
|
||||
}
|
||||
String value = cursor.getString(mIconName1Col);
|
||||
Drawable drawable = getDrawableFromResourceValue(value);
|
||||
if (drawable != null) {
|
||||
return drawable;
|
||||
}
|
||||
return getDefaultIcon1(cursor);
|
||||
}
|
||||
|
||||
private Drawable getIcon2(Cursor cursor) {
|
||||
if (mIconName2Col == INVALID_INDEX) {
|
||||
return null;
|
||||
}
|
||||
String value = cursor.getString(mIconName2Col);
|
||||
return getDrawableFromResourceValue(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the drawable in an image view, makes sure the view is only visible if there
|
||||
* is a drawable.
|
||||
*/
|
||||
private void setViewDrawable(ImageView v, Drawable drawable, int nullVisibility) {
|
||||
// Set the icon even if the drawable is null, since we need to clear any
|
||||
// previous icon.
|
||||
v.setImageDrawable(drawable);
|
||||
|
||||
if (drawable == null) {
|
||||
v.setVisibility(nullVisibility);
|
||||
} else {
|
||||
v.setVisibility(View.VISIBLE);
|
||||
|
||||
// This is a hack to get any animated drawables (like a 'working' spinner)
|
||||
// to animate. You have to setVisible true on an AnimationDrawable to get
|
||||
// it to start animating, but it must first have been false or else the
|
||||
// call to setVisible will be ineffective. We need to clear up the story
|
||||
// about animated drawables in the future, see http://b/1878430.
|
||||
drawable.setVisible(false, false);
|
||||
drawable.setVisible(true, false);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the text to show in the query field when a suggestion is selected.
|
||||
*
|
||||
* @param cursor The Cursor to read the suggestion data from. The Cursor should already
|
||||
* be moved to the suggestion that is to be read from.
|
||||
* @return The text to show, or <code>null</code> if the query should not be
|
||||
* changed when selecting this suggestion.
|
||||
*/
|
||||
@Override
|
||||
public CharSequence convertToString(Cursor cursor) {
|
||||
if (cursor == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
String query = getColumnString(cursor, SearchManager.SUGGEST_COLUMN_QUERY);
|
||||
if (query != null) {
|
||||
return query;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* This method is overridden purely to provide a bit of protection against
|
||||
* flaky content providers.
|
||||
*
|
||||
* @see android.widget.ListAdapter#getView(int, View, ViewGroup)
|
||||
*/
|
||||
@Override
|
||||
public View getView(int position, View convertView, ViewGroup parent) {
|
||||
try {
|
||||
return super.getView(position, convertView, parent);
|
||||
} catch (RuntimeException e) {
|
||||
Log.w(LOG_TAG, "Search suggestions cursor threw exception.", e);
|
||||
// Put exception string in item title
|
||||
View v = newView(mContext, mCursor, parent);
|
||||
if (v != null) {
|
||||
ChildViewCache views = (ChildViewCache) v.getTag();
|
||||
TextView tv = views.mText1;
|
||||
tv.setText(e.toString());
|
||||
}
|
||||
return v;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a drawable given a value provided by a suggestion provider.
|
||||
*
|
||||
* This value could be just the string value of a resource id
|
||||
* (e.g., "2130837524"), in which case we will try to retrieve a drawable from
|
||||
* the provider's resources. If the value is not an integer, it is
|
||||
* treated as a Uri and opened with
|
||||
* {@link ContentResolver#openOutputStream(android.net.Uri, String)}.
|
||||
*
|
||||
* All resources and URIs are read using the suggestion provider's context.
|
||||
*
|
||||
* If the string is not formatted as expected, or no drawable can be found for
|
||||
* the provided value, this method returns null.
|
||||
*
|
||||
* @param drawableId a string like "2130837524",
|
||||
* "android.resource://com.android.alarmclock/2130837524",
|
||||
* or "content://contacts/photos/253".
|
||||
* @return a Drawable, or null if none found
|
||||
*/
|
||||
private Drawable getDrawableFromResourceValue(String drawableId) {
|
||||
if (drawableId == null || drawableId.length() == 0 || "0".equals(drawableId)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
// First, see if it's just an integer
|
||||
int resourceId = Integer.parseInt(drawableId);
|
||||
// It's an int, look for it in the cache
|
||||
String drawableUri = ContentResolver.SCHEME_ANDROID_RESOURCE
|
||||
+ "://" + mProviderContext.getPackageName() + "/" + resourceId;
|
||||
// Must use URI as cache key, since ints are app-specific
|
||||
Drawable drawable = checkIconCache(drawableUri);
|
||||
if (drawable != null) {
|
||||
return drawable;
|
||||
}
|
||||
// Not cached, find it by resource ID
|
||||
drawable = mProviderContext.getResources().getDrawable(resourceId);
|
||||
// Stick it in the cache, using the URI as key
|
||||
storeInIconCache(drawableUri, drawable);
|
||||
return drawable;
|
||||
} catch (NumberFormatException nfe) {
|
||||
// It's not an integer, use it as a URI
|
||||
Drawable drawable = checkIconCache(drawableId);
|
||||
if (drawable != null) {
|
||||
return drawable;
|
||||
}
|
||||
Uri uri = Uri.parse(drawableId);
|
||||
drawable = getDrawable(uri);
|
||||
storeInIconCache(drawableId, drawable);
|
||||
return drawable;
|
||||
} catch (Resources.NotFoundException nfe) {
|
||||
// It was an integer, but it couldn't be found, bail out
|
||||
Log.w(LOG_TAG, "Icon resource not found: " + drawableId);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a drawable by URI, without using the cache.
|
||||
*
|
||||
* @return A drawable, or {@code null} if the drawable could not be loaded.
|
||||
*/
|
||||
private Drawable getDrawable(Uri uri) {
|
||||
try {
|
||||
String scheme = uri.getScheme();
|
||||
if (ContentResolver.SCHEME_ANDROID_RESOURCE.equals(scheme)) {
|
||||
// Load drawables through Resources, to get the source density information
|
||||
try {
|
||||
return getTheDrawable(uri);
|
||||
} catch (Resources.NotFoundException ex) {
|
||||
throw new FileNotFoundException("Resource does not exist: " + uri);
|
||||
}
|
||||
} else {
|
||||
// Let the ContentResolver handle content and file URIs.
|
||||
InputStream stream = mProviderContext.getContentResolver().openInputStream(uri);
|
||||
if (stream == null) {
|
||||
throw new FileNotFoundException("Failed to open " + uri);
|
||||
}
|
||||
try {
|
||||
return Drawable.createFromStream(stream, null);
|
||||
} finally {
|
||||
try {
|
||||
stream.close();
|
||||
} catch (IOException ex) {
|
||||
Log.e(LOG_TAG, "Error closing icon stream for " + uri, ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (FileNotFoundException fnfe) {
|
||||
Log.w(LOG_TAG, "Icon not found: " + uri + ", " + fnfe.getMessage());
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Drawable getTheDrawable(Uri uri) throws FileNotFoundException {
|
||||
String authority = uri.getAuthority();
|
||||
Resources r;
|
||||
if (TextUtils.isEmpty(authority)) {
|
||||
throw new FileNotFoundException("No authority: " + uri);
|
||||
} else {
|
||||
try {
|
||||
r = mContext.getPackageManager().getResourcesForApplication(authority);
|
||||
} catch (NameNotFoundException ex) {
|
||||
throw new FileNotFoundException("No package found for authority: " + uri);
|
||||
}
|
||||
}
|
||||
List<String> path = uri.getPathSegments();
|
||||
if (path == null) {
|
||||
throw new FileNotFoundException("No path: " + uri);
|
||||
}
|
||||
int len = path.size();
|
||||
int id;
|
||||
if (len == 1) {
|
||||
try {
|
||||
id = Integer.parseInt(path.get(0));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new FileNotFoundException("Single path segment is not a resource ID: " + uri);
|
||||
}
|
||||
} else if (len == 2) {
|
||||
id = r.getIdentifier(path.get(1), path.get(0), authority);
|
||||
} else {
|
||||
throw new FileNotFoundException("More than two path segments: " + uri);
|
||||
}
|
||||
if (id == 0) {
|
||||
throw new FileNotFoundException("No resource found for: " + uri);
|
||||
}
|
||||
return r.getDrawable(id);
|
||||
}
|
||||
|
||||
private Drawable checkIconCache(String resourceUri) {
|
||||
Drawable.ConstantState cached = mOutsideDrawablesCache.get(resourceUri);
|
||||
if (cached == null) {
|
||||
return null;
|
||||
}
|
||||
if (DBG) Log.d(LOG_TAG, "Found icon in cache: " + resourceUri);
|
||||
return cached.newDrawable();
|
||||
}
|
||||
|
||||
private void storeInIconCache(String resourceUri, Drawable drawable) {
|
||||
if (drawable != null) {
|
||||
mOutsideDrawablesCache.put(resourceUri, drawable.getConstantState());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the left-hand side icon that will be used for the current suggestion
|
||||
* if the suggestion contains an icon column but no icon or a broken icon.
|
||||
*
|
||||
* @param cursor A cursor positioned at the current suggestion.
|
||||
* @return A non-null drawable.
|
||||
*/
|
||||
private Drawable getDefaultIcon1(Cursor cursor) {
|
||||
// Fall back to a default icon
|
||||
return mContext.getPackageManager().getDefaultActivityIcon();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the activity or application icon for an activity.
|
||||
* Uses the local icon cache for fast repeated lookups.
|
||||
*
|
||||
* @param component Name of an activity.
|
||||
* @return A drawable, or {@code null} if neither the activity nor the application
|
||||
* has an icon set.
|
||||
*/
|
||||
private Drawable getActivityIconWithCache(ComponentName component) {
|
||||
// First check the icon cache
|
||||
String componentIconKey = component.flattenToShortString();
|
||||
// Using containsKey() since we also store null values.
|
||||
if (mOutsideDrawablesCache.containsKey(componentIconKey)) {
|
||||
Drawable.ConstantState cached = mOutsideDrawablesCache.get(componentIconKey);
|
||||
return cached == null ? null : cached.newDrawable(mProviderContext.getResources());
|
||||
}
|
||||
// Then try the activity or application icon
|
||||
Drawable drawable = getActivityIcon(component);
|
||||
// Stick it in the cache so we don't do this lookup again.
|
||||
Drawable.ConstantState toCache = drawable == null ? null : drawable.getConstantState();
|
||||
mOutsideDrawablesCache.put(componentIconKey, toCache);
|
||||
return drawable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the activity or application icon for an activity.
|
||||
*
|
||||
* @param component Name of an activity.
|
||||
* @return A drawable, or {@code null} if neither the acitivy or the application
|
||||
* have an icon set.
|
||||
*/
|
||||
private Drawable getActivityIcon(ComponentName component) {
|
||||
PackageManager pm = mContext.getPackageManager();
|
||||
final ActivityInfo activityInfo;
|
||||
try {
|
||||
activityInfo = pm.getActivityInfo(component, PackageManager.GET_META_DATA);
|
||||
} catch (NameNotFoundException ex) {
|
||||
Log.w(LOG_TAG, ex.toString());
|
||||
return null;
|
||||
}
|
||||
int iconId = activityInfo.getIconResource();
|
||||
if (iconId == 0) return null;
|
||||
String pkg = component.getPackageName();
|
||||
Drawable drawable = pm.getDrawable(pkg, iconId, activityInfo.applicationInfo);
|
||||
if (drawable == null) {
|
||||
Log.w(LOG_TAG, "Invalid icon resource " + iconId + " for "
|
||||
+ component.flattenToShortString());
|
||||
return null;
|
||||
}
|
||||
return drawable;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the value of a string column by name.
|
||||
*
|
||||
* @param cursor Cursor to read the value from.
|
||||
* @param columnName The name of the column to read.
|
||||
* @return The value of the given column, or <code>null</null>
|
||||
* if the cursor does not contain the given column.
|
||||
*/
|
||||
public static String getColumnString(Cursor cursor, String columnName) {
|
||||
int col = cursor.getColumnIndex(columnName);
|
||||
return getStringOrNull(cursor, col);
|
||||
}
|
||||
|
||||
private static String getStringOrNull(Cursor cursor, int col) {
|
||||
if (col == INVALID_INDEX) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return cursor.getString(col);
|
||||
} catch (Exception e) {
|
||||
Log.e(LOG_TAG,
|
||||
"unexpected error retrieving valid column from cursor, "
|
||||
+ "did the remote process die?", e);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Reference in a new issue