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 package com.android.internal.view.menu; 17 18 import com.android.internal.view.menu.MenuView.ItemView; 19 20 import android.annotation.NonNull; 21 import android.annotation.Nullable; 22 import android.content.Context; 23 import android.os.Bundle; 24 import android.os.Parcelable; 25 import android.util.SparseArray; 26 import android.view.ContextThemeWrapper; 27 import android.view.MenuItem; 28 import android.view.View; 29 import android.view.ViewGroup; 30 31 import java.util.ArrayList; 32 33 /** 34 * MenuPresenter for the classic "six-pack" icon menu. 35 */ 36 public class IconMenuPresenter extends BaseMenuPresenter { 37 private IconMenuItemView mMoreView; 38 private int mMaxItems = -1; 39 40 int mOpenSubMenuId; 41 SubMenuPresenterCallback mSubMenuPresenterCallback = new SubMenuPresenterCallback(); 42 MenuDialogHelper mOpenSubMenu; 43 44 private static final String VIEWS_TAG = "android:menu:icon"; 45 private static final String OPEN_SUBMENU_KEY = "android:menu:icon:submenu"; 46 IconMenuPresenter(Context context)47 public IconMenuPresenter(Context context) { 48 super(new ContextThemeWrapper(context, com.android.internal.R.style.Theme_IconMenu), 49 com.android.internal.R.layout.icon_menu_layout, 50 com.android.internal.R.layout.icon_menu_item_layout); 51 } 52 53 @Override initForMenu(@onNull Context context, @Nullable MenuBuilder menu)54 public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) { 55 super.initForMenu(context, menu); 56 mMaxItems = -1; 57 } 58 59 @Override bindItemView(MenuItemImpl item, ItemView itemView)60 public void bindItemView(MenuItemImpl item, ItemView itemView) { 61 final IconMenuItemView view = (IconMenuItemView) itemView; 62 view.setItemData(item); 63 64 view.initialize(item.getTitleForItemView(view), item.getIcon()); 65 66 view.setVisibility(item.isVisible() ? View.VISIBLE : View.GONE); 67 view.setEnabled(view.isEnabled()); 68 view.setLayoutParams(view.getTextAppropriateLayoutParams()); 69 } 70 71 @Override shouldIncludeItem(int childIndex, MenuItemImpl item)72 public boolean shouldIncludeItem(int childIndex, MenuItemImpl item) { 73 final ArrayList<MenuItemImpl> itemsToShow = mMenu.getNonActionItems(); 74 boolean fits = (itemsToShow.size() == mMaxItems && childIndex < mMaxItems) || 75 childIndex < mMaxItems - 1; 76 return fits && !item.isActionButton(); 77 } 78 79 @Override 80 protected void addItemView(View itemView, int childIndex) { 81 final IconMenuItemView v = (IconMenuItemView) itemView; 82 final IconMenuView parent = (IconMenuView) mMenuView; 83 84 v.setIconMenuView(parent); 85 v.setItemInvoker(parent); 86 v.setBackgroundDrawable(parent.getItemBackgroundDrawable()); 87 super.addItemView(itemView, childIndex); 88 } 89 90 @Override 91 public boolean onSubMenuSelected(SubMenuBuilder subMenu) { 92 if (!subMenu.hasVisibleItems()) return false; 93 94 // The window manager will give us a token. 95 MenuDialogHelper helper = new MenuDialogHelper(subMenu); 96 helper.setPresenterCallback(mSubMenuPresenterCallback); 97 helper.show(null); 98 mOpenSubMenu = helper; 99 mOpenSubMenuId = subMenu.getItem().getItemId(); 100 super.onSubMenuSelected(subMenu); 101 return true; 102 } 103 104 @Override 105 public void updateMenuView(boolean cleared) { 106 final IconMenuView menuView = (IconMenuView) mMenuView; 107 if (mMaxItems < 0) mMaxItems = menuView.getMaxItems(); 108 final ArrayList<MenuItemImpl> itemsToShow = mMenu.getNonActionItems(); 109 final boolean needsMore = itemsToShow.size() > mMaxItems; 110 super.updateMenuView(cleared); 111 112 if (needsMore && (mMoreView == null || mMoreView.getParent() != menuView)) { 113 if (mMoreView == null) { 114 mMoreView = menuView.createMoreItemView(); 115 mMoreView.setBackgroundDrawable(menuView.getItemBackgroundDrawable()); 116 } 117 menuView.addView(mMoreView); 118 } else if (!needsMore && mMoreView != null) { 119 menuView.removeView(mMoreView); 120 } 121 122 menuView.setNumActualItemsShown(needsMore ? mMaxItems - 1 : itemsToShow.size()); 123 } 124 125 @Override 126 protected boolean filterLeftoverView(ViewGroup parent, int childIndex) { 127 if (parent.getChildAt(childIndex) != mMoreView) { 128 return super.filterLeftoverView(parent, childIndex); 129 } 130 return false; 131 } 132 133 public int getNumActualItemsShown() { 134 return ((IconMenuView) mMenuView).getNumActualItemsShown(); 135 } 136 137 public void saveHierarchyState(Bundle outState) { 138 SparseArray<Parcelable> viewStates = new SparseArray<Parcelable>(); 139 if (mMenuView != null) { 140 ((View) mMenuView).saveHierarchyState(viewStates); 141 } 142 outState.putSparseParcelableArray(VIEWS_TAG, viewStates); 143 } 144 145 public void restoreHierarchyState(Bundle inState) { 146 SparseArray<Parcelable> viewStates = inState.getSparseParcelableArray(VIEWS_TAG); 147 if (viewStates != null) { 148 ((View) mMenuView).restoreHierarchyState(viewStates); 149 } 150 int subMenuId = inState.getInt(OPEN_SUBMENU_KEY, 0); 151 if (subMenuId > 0 && mMenu != null) { 152 MenuItem item = mMenu.findItem(subMenuId); 153 if (item != null) { 154 onSubMenuSelected((SubMenuBuilder) item.getSubMenu()); 155 } 156 } 157 } 158 159 @Override 160 public Parcelable onSaveInstanceState() { 161 if (mMenuView == null) { 162 return null; 163 } 164 165 Bundle state = new Bundle(); 166 saveHierarchyState(state); 167 if (mOpenSubMenuId > 0) { 168 state.putInt(OPEN_SUBMENU_KEY, mOpenSubMenuId); 169 } 170 return state; 171 } 172 173 @Override 174 public void onRestoreInstanceState(Parcelable state) { 175 restoreHierarchyState((Bundle) state); 176 } 177 178 class SubMenuPresenterCallback implements MenuPresenter.Callback { 179 @Override 180 public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) { 181 mOpenSubMenuId = 0; 182 if (mOpenSubMenu != null) { 183 mOpenSubMenu.dismiss(); 184 mOpenSubMenu = null; 185 } 186 } 187 188 @Override 189 public boolean onOpenSubMenu(MenuBuilder subMenu) { 190 if (subMenu != null) { 191 mOpenSubMenuId = ((SubMenuBuilder) subMenu).getItem().getItemId(); 192 } 193 return false; 194 } 195 196 } 197 } 198