ListMenuPresenter.java revision 51195b56ff6d3d589abefde27f0a99b5a9a04ff8
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
17package com.android.internal.view.menu;
18
19import android.content.Context;
20import android.os.Bundle;
21import android.os.Parcelable;
22import android.util.SparseArray;
23import android.view.ContextThemeWrapper;
24import android.view.LayoutInflater;
25import android.view.View;
26import android.view.ViewGroup;
27import android.widget.AdapterView;
28import android.widget.BaseAdapter;
29import android.widget.ListAdapter;
30
31import java.util.ArrayList;
32
33/**
34 * MenuPresenter for list-style menus.
35 */
36public class ListMenuPresenter implements MenuPresenter, AdapterView.OnItemClickListener {
37    Context mContext;
38    LayoutInflater mInflater;
39    MenuBuilder mMenu;
40
41    ExpandedMenuView mMenuView;
42
43    private int mItemIndexOffset;
44    int mThemeRes;
45    int mItemLayoutRes;
46
47    private Callback mCallback;
48    private MenuAdapter mAdapter;
49
50    public static final String VIEWS_TAG = "android:menu:list";
51
52    /**
53     * Construct a new ListMenuPresenter.
54     * @param context Context to use for theming. This will supersede the context provided
55     *                to initForMenu when this presenter is added.
56     * @param itemLayoutRes Layout resource for individual item views.
57     */
58    public ListMenuPresenter(Context context, int itemLayoutRes) {
59        this(itemLayoutRes, 0);
60        mContext = context;
61    }
62
63    /**
64     * Construct a new ListMenuPresenter.
65     * @param itemLayoutRes Layout resource for individual item views.
66     * @param themeRes Resource ID of a theme to use for views.
67     */
68    public ListMenuPresenter(int itemLayoutRes, int themeRes) {
69        mItemLayoutRes = itemLayoutRes;
70        mThemeRes = themeRes;
71    }
72
73    @Override
74    public void initForMenu(Context context, MenuBuilder menu) {
75        if (mThemeRes != 0) {
76            mContext = new ContextThemeWrapper(context, mThemeRes);
77        } else if (mContext == null) {
78            mContext = context;
79        }
80        mInflater = LayoutInflater.from(mContext);
81        mMenu = menu;
82    }
83
84    @Override
85    public MenuView getMenuView(ViewGroup root) {
86        if (mMenuView == null) {
87            mMenuView = (ExpandedMenuView) mInflater.inflate(
88                    com.android.internal.R.layout.expanded_menu_layout, root, false);
89            if (mAdapter == null) {
90                mAdapter = new MenuAdapter();
91            }
92            mMenuView.setAdapter(mAdapter);
93            mMenuView.setOnItemClickListener(this);
94        }
95        return mMenuView;
96    }
97
98    /**
99     * Call this instead of getMenuView if you want to manage your own ListView.
100     * For proper operation, the ListView hosting this adapter should add
101     * this presenter as an OnItemClickListener.
102     *
103     * @return A ListAdapter containing the items in the menu.
104     */
105    public ListAdapter getAdapter() {
106        if (mAdapter == null) {
107            mAdapter = new MenuAdapter();
108        }
109        return mAdapter;
110    }
111
112    @Override
113    public void updateMenuView(boolean cleared) {
114        if (mAdapter != null) mAdapter.notifyDataSetChanged();
115    }
116
117    @Override
118    public void setCallback(Callback cb) {
119        mCallback = cb;
120    }
121
122    @Override
123    public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
124        if (!subMenu.hasVisibleItems()) return false;
125
126        // The window manager will give us a token.
127        new MenuDialogHelper(subMenu).show(null);
128        if (mCallback != null) {
129            mCallback.onOpenSubMenu(subMenu);
130        }
131        return true;
132    }
133
134    @Override
135    public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
136        if (mCallback != null) {
137            mCallback.onCloseMenu(menu, allMenusAreClosing);
138        }
139    }
140
141    int getItemIndexOffset() {
142        return mItemIndexOffset;
143    }
144
145    public void setItemIndexOffset(int offset) {
146        mItemIndexOffset = offset;
147        if (mMenuView != null) {
148            updateMenuView(false);
149        }
150    }
151
152    @Override
153    public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
154        mMenu.performItemAction(mAdapter.getItem(position), 0);
155    }
156
157    @Override
158    public boolean flagActionItems() {
159        return false;
160    }
161
162    public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
163        return false;
164    }
165
166    public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
167        return false;
168    }
169
170    public void saveHierarchyState(Bundle outState) {
171        SparseArray<Parcelable> viewStates = new SparseArray<Parcelable>();
172        if (mMenuView != null) {
173            ((View) mMenuView).saveHierarchyState(viewStates);
174        }
175        outState.putSparseParcelableArray(VIEWS_TAG, viewStates);
176    }
177
178    public void restoreHierarchyState(Bundle inState) {
179        SparseArray<Parcelable> viewStates = inState.getSparseParcelableArray(VIEWS_TAG);
180        if (viewStates != null) {
181            ((View) mMenuView).restoreHierarchyState(viewStates);
182        }
183    }
184
185    private class MenuAdapter extends BaseAdapter {
186        public int getCount() {
187            ArrayList<MenuItemImpl> items = mMenu.getNonActionItems();
188            return items.size() - mItemIndexOffset;
189        }
190
191        public MenuItemImpl getItem(int position) {
192            ArrayList<MenuItemImpl> items = mMenu.getNonActionItems();
193            return items.get(position + mItemIndexOffset);
194        }
195
196        public long getItemId(int position) {
197            // Since a menu item's ID is optional, we'll use the position as an
198            // ID for the item in the AdapterView
199            return position;
200        }
201
202        public View getView(int position, View convertView, ViewGroup parent) {
203            if (convertView == null) {
204                convertView = mInflater.inflate(mItemLayoutRes, parent, false);
205            }
206
207            MenuView.ItemView itemView = (MenuView.ItemView) convertView;
208            itemView.initialize(getItem(position), 0);
209            return convertView;
210        }
211    }
212}
213