Home | History | Annotate | Download | only in widget
      1 /*
      2  * Copyright (C) 2010 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.widget;
     18 
     19 import com.android.internal.view.menu.MenuBuilder;
     20 import com.android.internal.view.menu.MenuPopupHelper;
     21 import com.android.internal.view.menu.MenuPresenter;
     22 import com.android.internal.view.menu.SubMenuBuilder;
     23 
     24 import android.content.Context;
     25 import android.view.Menu;
     26 import android.view.MenuInflater;
     27 import android.view.MenuItem;
     28 import android.view.View;
     29 
     30 /**
     31  * A PopupMenu displays a {@link Menu} in a modal popup window anchored to a {@link View}.
     32  * The popup will appear below the anchor view if there is room, or above it if there is not.
     33  * If the IME is visible the popup will not overlap it until it is touched. Touching outside
     34  * of the popup will dismiss it.
     35  */
     36 public class PopupMenu implements MenuBuilder.Callback, MenuPresenter.Callback {
     37     private Context mContext;
     38     private MenuBuilder mMenu;
     39     private View mAnchor;
     40     private MenuPopupHelper mPopup;
     41     private OnMenuItemClickListener mMenuItemClickListener;
     42     private OnDismissListener mDismissListener;
     43 
     44     /**
     45      * Callback interface used to notify the application that the menu has closed.
     46      */
     47     public interface OnDismissListener {
     48         /**
     49          * Called when the associated menu has been dismissed.
     50          *
     51          * @param menu The PopupMenu that was dismissed.
     52          */
     53         public void onDismiss(PopupMenu menu);
     54     }
     55 
     56     /**
     57      * Construct a new PopupMenu.
     58      *
     59      * @param context Context for the PopupMenu.
     60      * @param anchor Anchor view for this popup. The popup will appear below the anchor if there
     61      *               is room, or above it if there is not.
     62      */
     63     public PopupMenu(Context context, View anchor) {
     64         // TODO Theme?
     65         mContext = context;
     66         mMenu = new MenuBuilder(context);
     67         mMenu.setCallback(this);
     68         mAnchor = anchor;
     69         mPopup = new MenuPopupHelper(context, mMenu, anchor);
     70         mPopup.setCallback(this);
     71     }
     72 
     73     /**
     74      * @return the {@link Menu} associated with this popup. Populate the returned Menu with
     75      * items before calling {@link #show()}.
     76      *
     77      * @see #show()
     78      * @see #getMenuInflater()
     79      */
     80     public Menu getMenu() {
     81         return mMenu;
     82     }
     83 
     84     /**
     85      * @return a {@link MenuInflater} that can be used to inflate menu items from XML into the
     86      * menu returned by {@link #getMenu()}.
     87      *
     88      * @see #getMenu()
     89      */
     90     public MenuInflater getMenuInflater() {
     91         return new MenuInflater(mContext);
     92     }
     93 
     94     /**
     95      * Inflate a menu resource into this PopupMenu. This is equivalent to calling
     96      * popupMenu.getMenuInflater().inflate(menuRes, popupMenu.getMenu()).
     97      * @param menuRes Menu resource to inflate
     98      */
     99     public void inflate(int menuRes) {
    100         getMenuInflater().inflate(menuRes, mMenu);
    101     }
    102 
    103     /**
    104      * Show the menu popup anchored to the view specified during construction.
    105      * @see #dismiss()
    106      */
    107     public void show() {
    108         mPopup.show();
    109     }
    110 
    111     /**
    112      * Dismiss the menu popup.
    113      * @see #show()
    114      */
    115     public void dismiss() {
    116         mPopup.dismiss();
    117     }
    118 
    119     /**
    120      * Set a listener that will be notified when the user selects an item from the menu.
    121      *
    122      * @param listener Listener to notify
    123      */
    124     public void setOnMenuItemClickListener(OnMenuItemClickListener listener) {
    125         mMenuItemClickListener = listener;
    126     }
    127 
    128     /**
    129      * Set a listener that will be notified when this menu is dismissed.
    130      *
    131      * @param listener Listener to notify
    132      */
    133     public void setOnDismissListener(OnDismissListener listener) {
    134         mDismissListener = listener;
    135     }
    136 
    137     /**
    138      * @hide
    139      */
    140     public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
    141         if (mMenuItemClickListener != null) {
    142             return mMenuItemClickListener.onMenuItemClick(item);
    143         }
    144         return false;
    145     }
    146 
    147     /**
    148      * @hide
    149      */
    150     public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
    151         if (mDismissListener != null) {
    152             mDismissListener.onDismiss(this);
    153         }
    154     }
    155 
    156     /**
    157      * @hide
    158      */
    159     public boolean onOpenSubMenu(MenuBuilder subMenu) {
    160         if (subMenu == null) return false;
    161 
    162         if (!subMenu.hasVisibleItems()) {
    163             return true;
    164         }
    165 
    166         // Current menu will be dismissed by the normal helper, submenu will be shown in its place.
    167         new MenuPopupHelper(mContext, subMenu, mAnchor).show();
    168         return true;
    169     }
    170 
    171     /**
    172      * @hide
    173      */
    174     public void onCloseSubMenu(SubMenuBuilder menu) {
    175     }
    176 
    177     /**
    178      * @hide
    179      */
    180     public void onMenuModeChange(MenuBuilder menu) {
    181     }
    182 
    183     /**
    184      * Interface responsible for receiving menu item click events if the items themselves
    185      * do not have individual item click listeners.
    186      */
    187     public interface OnMenuItemClickListener {
    188         /**
    189          * This method will be invoked when a menu item is clicked if the item itself did
    190          * not already handle the event.
    191          *
    192          * @param item {@link MenuItem} that was clicked
    193          * @return <code>true</code> if the event was handled, <code>false</code> otherwise.
    194          */
    195         public boolean onMenuItemClick(MenuItem item);
    196     }
    197 }
    198