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