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