blob: 2cb2a100c01138aeb4e3bb1f2bf4c7577ed5ce88 [file] [log] [blame]
Adam Powell696cba52011-03-29 10:38:16 -07001/*
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 void saveHierarchyState(Bundle outState) {
163 SparseArray<Parcelable> viewStates = new SparseArray<Parcelable>();
164 if (mMenuView != null) {
165 ((View) mMenuView).saveHierarchyState(viewStates);
166 }
167 outState.putSparseParcelableArray(VIEWS_TAG, viewStates);
168 }
169
170 public void restoreHierarchyState(Bundle inState) {
171 SparseArray<Parcelable> viewStates = inState.getSparseParcelableArray(VIEWS_TAG);
172 ((View) mMenuView).restoreHierarchyState(viewStates);
173 }
174
175 private class MenuAdapter extends BaseAdapter {
176 public int getCount() {
177 ArrayList<MenuItemImpl> items = mMenu.getVisibleItems();
178 return items.size() - mItemIndexOffset;
179 }
180
181 public MenuItemImpl getItem(int position) {
182 ArrayList<MenuItemImpl> items = mMenu.getVisibleItems();
183 return items.get(position + mItemIndexOffset);
184 }
185
186 public long getItemId(int position) {
187 // Since a menu item's ID is optional, we'll use the position as an
188 // ID for the item in the AdapterView
189 return position;
190 }
191
192 public View getView(int position, View convertView, ViewGroup parent) {
193 if (convertView == null) {
194 convertView = mInflater.inflate(mItemLayoutRes, parent, false);
195 }
196
197 MenuView.ItemView itemView = (MenuView.ItemView) convertView;
198 itemView.initialize(getItem(position), 0);
199 return convertView;
200 }
201 }
202}