Home | History | Annotate | Download | only in menu
      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 com.android.internal.view.menu;
     18 
     19 import android.content.Context;
     20 import android.view.LayoutInflater;
     21 import android.view.View;
     22 import android.view.ViewGroup;
     23 
     24 import java.util.ArrayList;
     25 
     26 /**
     27  * Base class for MenuPresenters that have a consistent container view and item
     28  * views. Behaves similarly to an AdapterView in that existing item views will
     29  * be reused if possible when items change.
     30  */
     31 public abstract class BaseMenuPresenter implements MenuPresenter {
     32     protected Context mSystemContext;
     33     protected Context mContext;
     34     protected MenuBuilder mMenu;
     35     protected LayoutInflater mSystemInflater;
     36     protected LayoutInflater mInflater;
     37     private Callback mCallback;
     38 
     39     private int mMenuLayoutRes;
     40     private int mItemLayoutRes;
     41 
     42     protected MenuView mMenuView;
     43 
     44     private int mId;
     45 
     46     /**
     47      * Construct a new BaseMenuPresenter.
     48      *
     49      * @param context Context for generating system-supplied views
     50      * @param menuLayoutRes Layout resource ID for the menu container view
     51      * @param itemLayoutRes Layout resource ID for a single item view
     52      */
     53     public BaseMenuPresenter(Context context, int menuLayoutRes, int itemLayoutRes) {
     54         mSystemContext = context;
     55         mSystemInflater = LayoutInflater.from(context);
     56         mMenuLayoutRes = menuLayoutRes;
     57         mItemLayoutRes = itemLayoutRes;
     58     }
     59 
     60     @Override
     61     public void initForMenu(Context context, MenuBuilder menu) {
     62         mContext = context;
     63         mInflater = LayoutInflater.from(mContext);
     64         mMenu = menu;
     65     }
     66 
     67     @Override
     68     public MenuView getMenuView(ViewGroup root) {
     69         if (mMenuView == null) {
     70             mMenuView = (MenuView) mSystemInflater.inflate(mMenuLayoutRes, root, false);
     71             mMenuView.initialize(mMenu);
     72             updateMenuView(true);
     73         }
     74 
     75         return mMenuView;
     76     }
     77 
     78     /**
     79      * Reuses item views when it can
     80      */
     81     public void updateMenuView(boolean cleared) {
     82         final ViewGroup parent = (ViewGroup) mMenuView;
     83         if (parent == null) return;
     84 
     85         int childIndex = 0;
     86         if (mMenu != null) {
     87             mMenu.flagActionItems();
     88             ArrayList<MenuItemImpl> visibleItems = mMenu.getVisibleItems();
     89             final int itemCount = visibleItems.size();
     90             for (int i = 0; i < itemCount; i++) {
     91                 MenuItemImpl item = visibleItems.get(i);
     92                 if (shouldIncludeItem(childIndex, item)) {
     93                     final View convertView = parent.getChildAt(childIndex);
     94                     final MenuItemImpl oldItem = convertView instanceof MenuView.ItemView ?
     95                             ((MenuView.ItemView) convertView).getItemData() : null;
     96                     final View itemView = getItemView(item, convertView, parent);
     97                     if (item != oldItem) {
     98                         // Don't let old states linger with new data.
     99                         itemView.setPressed(false);
    100                         itemView.jumpDrawablesToCurrentState();
    101                     }
    102                     if (itemView != convertView) {
    103                         addItemView(itemView, childIndex);
    104                     }
    105                     childIndex++;
    106                 }
    107             }
    108         }
    109 
    110         // Remove leftover views.
    111         while (childIndex < parent.getChildCount()) {
    112             if (!filterLeftoverView(parent, childIndex)) {
    113                 childIndex++;
    114             }
    115         }
    116     }
    117 
    118     /**
    119      * Add an item view at the given index.
    120      *
    121      * @param itemView View to add
    122      * @param childIndex Index within the parent to insert at
    123      */
    124     protected void addItemView(View itemView, int childIndex) {
    125         final ViewGroup currentParent = (ViewGroup) itemView.getParent();
    126         if (currentParent != null) {
    127             currentParent.removeView(itemView);
    128         }
    129         ((ViewGroup) mMenuView).addView(itemView, childIndex);
    130     }
    131 
    132     /**
    133      * Filter the child view at index and remove it if appropriate.
    134      * @param parent Parent to filter from
    135      * @param childIndex Index to filter
    136      * @return true if the child view at index was removed
    137      */
    138     protected boolean filterLeftoverView(ViewGroup parent, int childIndex) {
    139         parent.removeViewAt(childIndex);
    140         return true;
    141     }
    142 
    143     public void setCallback(Callback cb) {
    144         mCallback = cb;
    145     }
    146 
    147     public Callback getCallback() {
    148         return mCallback;
    149     }
    150 
    151     /**
    152      * Create a new item view that can be re-bound to other item data later.
    153      *
    154      * @return The new item view
    155      */
    156     public MenuView.ItemView createItemView(ViewGroup parent) {
    157         return (MenuView.ItemView) mSystemInflater.inflate(mItemLayoutRes, parent, false);
    158     }
    159 
    160     /**
    161      * Prepare an item view for use. See AdapterView for the basic idea at work here.
    162      * This may require creating a new item view, but well-behaved implementations will
    163      * re-use the view passed as convertView if present. The returned view will be populated
    164      * with data from the item parameter.
    165      *
    166      * @param item Item to present
    167      * @param convertView Existing view to reuse
    168      * @param parent Intended parent view - use for inflation.
    169      * @return View that presents the requested menu item
    170      */
    171     public View getItemView(MenuItemImpl item, View convertView, ViewGroup parent) {
    172         MenuView.ItemView itemView;
    173         if (convertView instanceof MenuView.ItemView) {
    174             itemView = (MenuView.ItemView) convertView;
    175         } else {
    176             itemView = createItemView(parent);
    177         }
    178         bindItemView(item, itemView);
    179         return (View) itemView;
    180     }
    181 
    182     /**
    183      * Bind item data to an existing item view.
    184      *
    185      * @param item Item to bind
    186      * @param itemView View to populate with item data
    187      */
    188     public abstract void bindItemView(MenuItemImpl item, MenuView.ItemView itemView);
    189 
    190     /**
    191      * Filter item by child index and item data.
    192      *
    193      * @param childIndex Indended presentation index of this item
    194      * @param item Item to present
    195      * @return true if this item should be included in this menu presentation; false otherwise
    196      */
    197     public boolean shouldIncludeItem(int childIndex, MenuItemImpl item) {
    198         return true;
    199     }
    200 
    201     public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
    202         if (mCallback != null) {
    203             mCallback.onCloseMenu(menu, allMenusAreClosing);
    204         }
    205     }
    206 
    207     public boolean onSubMenuSelected(SubMenuBuilder menu) {
    208         if (mCallback != null) {
    209             return mCallback.onOpenSubMenu(menu);
    210         }
    211         return false;
    212     }
    213 
    214     public boolean flagActionItems() {
    215         return false;
    216     }
    217 
    218     public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
    219         return false;
    220     }
    221 
    222     public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
    223         return false;
    224     }
    225 
    226     public int getId() {
    227         return mId;
    228     }
    229 
    230     public void setId(int id) {
    231         mId = id;
    232     }
    233 }
    234