ActionProvider.java revision 34452b0d1034da026b8a1d6fe2fe4399844379d6
1/*
2 * Copyright (C) 2011 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package android.support.v4.view;
18
19import android.content.Context;
20import android.util.Log;
21import android.view.MenuItem;
22import android.view.SubMenu;
23import android.view.View;
24
25/**
26 * This class is a mediator for accomplishing a given task, for example sharing a file. It is
27 * responsible for creating a view that performs an action that accomplishes the task. This class
28 * also implements other functions such a performing a default action.
29 *
30 * <p>An ActionProvider can be
31 * optionally specified for a {@link android.view.MenuItem} and in such a case it will be
32 * responsible for
33 * creating the action view that appears in the {@link android.app.ActionBar} as a substitute for
34 * the menu item when the item is displayed as an action item. Also the provider is responsible for
35 * performing a default action if a menu item placed on the overflow menu of the ActionBar is
36 * selected and none of the menu item callbacks has handled the selection. For this case the
37 * provider can also optionally provide a sub-menu for accomplishing the task at hand.
38 *
39 * <p>There are two ways for using an action provider for creating and handling of action views:
40 *
41 * <ul><li> Setting the action provider on a {@link android.view.MenuItem} directly by
42 * calling {@link
43 * android.support.v4.view.MenuItemCompat#setActionProvider(android.view.MenuItem, ActionProvider)}.
44 * </li>
45 *
46 * <li>Declaring the action provider in the menu XML resource. For example:
47 *
48 * <pre>
49 * <code>
50 *   &lt;item android:id="@+id/my_menu_item"
51 *     android:title="Title"
52 *     android:icon="@drawable/my_menu_item_icon"
53 *     android:showAsAction="ifRoom"
54 *     android:actionProviderClass="foo.bar.SomeActionProvider" /&gt;
55 * </code>
56 * </pre>
57 * </li></ul></p>
58 *
59 * @see android.support.v4.view.MenuItemCompat#setActionProvider(android.view.MenuItem, ActionProvider)
60 * @see android.support.v4.view.MenuItemCompat#getActionProvider(android.view.MenuItem)
61 */
62public abstract class ActionProvider {
63    private static final String TAG = "ActionProvider(support)";
64    private final Context mContext;
65
66    private SubUiVisibilityListener mSubUiVisibilityListener;
67    private VisibilityListener mVisibilityListener;
68
69    /**
70     * Creates a new instance.
71     *
72     * @param context Context for accessing resources.
73     */
74    public ActionProvider(Context context) {
75        mContext = context;
76    }
77
78    /**
79     * Gets the context associated with this action provider.
80     */
81    public Context getContext() {
82        return mContext;
83    }
84
85    /**
86     * Factory method for creating new action views.
87     *
88     * @return A new action view.
89     */
90    public abstract View onCreateActionView();
91
92    /**
93     * Factory method called by the Android framework to create new action views.
94     * This method returns a new action view for the given MenuItem.
95     *
96     * <p>If your ActionProvider implementation overrides the deprecated no-argument overload
97     * {@link #onCreateActionView()}, overriding this method for devices running API 16 or later
98     * is recommended but optional. The default implementation calls {@link #onCreateActionView()}
99     * for compatibility with applications written for older platform versions.</p>
100     *
101     * @param forItem MenuItem to create the action view for
102     * @return the new action view
103     */
104    public View onCreateActionView(MenuItem forItem) {
105        return onCreateActionView();
106    }
107
108    /**
109     * The result of this method determines whether or not {@link #isVisible()} will be used
110     * by the {@link MenuItem} this ActionProvider is bound to help determine its visibility.
111     *
112     * @return true if this ActionProvider overrides the visibility of the MenuItem
113     *         it is bound to, false otherwise. The default implementation returns false.
114     * @see #isVisible()
115     */
116    public boolean overridesItemVisibility() {
117        return false;
118    }
119
120    /**
121     * If {@link #overridesItemVisibility()} returns true, the return value of this method
122     * will help determine the visibility of the {@link MenuItem} this ActionProvider is bound to.
123     *
124     * <p>If the MenuItem's visibility is explicitly set to false by the application,
125     * the MenuItem will not be shown, even if this method returns true.</p>
126     *
127     * @return true if the MenuItem this ActionProvider is bound to is visible, false if
128     *         it is invisible. The default implementation returns true.
129     */
130    public boolean isVisible() {
131        return true;
132    }
133
134    /**
135     * If this ActionProvider is associated with an item in a menu,
136     * refresh the visibility of the item based on {@link #overridesItemVisibility()} and
137     * {@link #isVisible()}. If {@link #overridesItemVisibility()} returns false, this call
138     * will have no effect.
139     */
140    public void refreshVisibility() {
141        if (mVisibilityListener != null && overridesItemVisibility()) {
142            mVisibilityListener.onActionProviderVisibilityChanged(isVisible());
143        }
144    }
145
146    /**
147     * Performs an optional default action.
148     *
149     * <p>For the case of an action provider placed in a menu
150     * item not shown as an action this method is invoked if previous callbacks for processing menu
151     * selection has handled the event.
152     *
153     * <p> A menu item selection is processed in the following order:
154     *
155     * <ul><li>Receiving a call to
156     * {@link android.view.MenuItem.OnMenuItemClickListener#onMenuItemClick
157     * MenuItem.OnMenuItemClickListener.onMenuItemClick}.</li>
158     *
159     * <li>Receiving a call to
160     * {@link android.app.Activity#onOptionsItemSelected(android.view.MenuItem)}
161     * FragmentActivity.onOptionsItemSelected(MenuItem)}
162     * </li>
163     *
164     * <li>Receiving a call to
165     * {@link android.support.v4.app.Fragment#onOptionsItemSelected(android.view.MenuItem)}
166     * Fragment.onOptionsItemSelected(MenuItem)}</li>
167     *
168     * <li>Launching the {@link android.content.Intent} set via
169     * {@link android.view.MenuItem#setIntent(android.content.Intent)
170     * MenuItem.setIntent(android.content.Intent)}
171     * </li>
172     *
173     * <li>Invoking this method.</li></ul>
174     *
175     * <p>The default implementation does not perform any action and returns false.
176     */
177    public boolean onPerformDefaultAction() {
178        return false;
179    }
180
181    /**
182     * Determines if this ActionProvider has a submenu associated with it.
183     *
184     * <p>Associated submenus will be shown when an action view is not. This provider instance will
185     * receive a call to {@link #onPrepareSubMenu(SubMenu)} after the call to {@link
186     * #onPerformDefaultAction()} and before a submenu is displayed to the user.
187     *
188     * @return true if the item backed by this provider should have an associated submenu
189     */
190    public boolean hasSubMenu() {
191        return false;
192    }
193
194    /**
195     * Called to prepare an associated submenu for the menu item backed by this ActionProvider.
196     *
197     * <p>if {@link #hasSubMenu()} returns true, this method will be called when the menu item is
198     * selected to prepare the submenu for presentation to the user. Apps may use this to create or
199     * alter submenu content right before display.
200     *
201     * @param subMenu Submenu that will be displayed
202     */
203    public void onPrepareSubMenu(SubMenu subMenu) {
204    }
205
206    /**
207     * Notify the system that the visibility of an action view's sub-UI such as an anchored popup
208     * has changed. This will affect how other system visibility notifications occur.
209     *
210     * @hide Pending future API approval
211     */
212    public void subUiVisibilityChanged(boolean isVisible) {
213        if (mSubUiVisibilityListener != null) {
214            mSubUiVisibilityListener.onSubUiVisibilityChanged(isVisible);
215        }
216    }
217
218    /**
219     * @hide Internal use only
220     */
221    public void setSubUiVisibilityListener(SubUiVisibilityListener listener) {
222        mSubUiVisibilityListener = listener;
223    }
224
225    /**
226     * Set a listener to be notified when this ActionProvider's overridden visibility changes.
227     * This should only be used by MenuItem implementations.
228     *
229     * @param listener listener to set
230     */
231    public void setVisibilityListener(VisibilityListener listener) {
232        if (mVisibilityListener != null && listener != null) {
233            Log.w(TAG, "setVisibilityListener: Setting a new ActionProvider.VisibilityListener " +
234                    "when one is already set. Are you reusing this " + getClass().getSimpleName() +
235                    " instance while it is still in use somewhere else?");
236        }
237        mVisibilityListener = listener;
238    }
239
240    /**
241     * @hide Internal use only
242     */
243    public interface SubUiVisibilityListener {
244
245        public void onSubUiVisibilityChanged(boolean isVisible);
246    }
247
248    /**
249     * Listens to changes in visibility as reported by {@link ActionProvider#refreshVisibility()}.
250     *
251     * @see ActionProvider#overridesItemVisibility()
252     * @see ActionProvider#isVisible()
253     */
254    public interface VisibilityListener {
255        public void onActionProviderVisibilityChanged(boolean isVisible);
256    }
257}
258