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