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.annotation.NonNull;
21import android.annotation.Nullable;
22import android.content.Context;
23import android.os.Bundle;
24import android.os.Parcelable;
25import android.util.SparseArray;
26import android.view.ContextThemeWrapper;
27import android.view.MenuItem;
28import android.view.View;
29import android.view.ViewGroup;
30
31import java.util.ArrayList;
32
33/**
34 * MenuPresenter for the classic "six-pack" icon menu.
35 */
36public 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
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
54    public void initForMenu(@NonNull Context context, @Nullable MenuBuilder menu) {
55        super.initForMenu(context, menu);
56        mMaxItems = -1;
57    }
58
59    @Override
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
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