Action Bar now supports submenus as popups.
Change-Id: I1691c16081b3474ed6d6e406f91f5f74a2dc8fcb
diff --git a/core/java/android/widget/ListPopupWindow.java b/core/java/android/widget/ListPopupWindow.java
index e9de385..5c34c2c 100644
--- a/core/java/android/widget/ListPopupWindow.java
+++ b/core/java/android/widget/ListPopupWindow.java
@@ -78,7 +78,7 @@
private AdapterView.OnItemClickListener mItemClickListener;
private AdapterView.OnItemSelectedListener mItemSelectedListener;
- private final ResizePopupRunnable mResizePopupRunnable = new ResizePopupRunnable();
+ private final ResizePopupRunnable mResizePopupRunnable = new ResizePopupRunnable();
private final PopupTouchInterceptor mTouchInterceptor = new PopupTouchInterceptor();
private final PopupScrollListener mScrollListener = new PopupScrollListener();
private final ListSelectorHider mHideSelector = new ListSelectorHider();
@@ -432,6 +432,19 @@
}
/**
+ * Sets the width of the popup window by the size of its content. The final width may be
+ * larger to accommodate styled window dressing.
+ *
+ * @param width Desired width of content in pixels.
+ */
+ public void setContentWidth(int width) {
+ Drawable popupBackground = mPopup.getBackground();
+ if (popupBackground != null) {
+ mDropDownWidth = popupBackground.getIntrinsicWidth() + width;
+ }
+ }
+
+ /**
* @return The height of the popup window in pixels.
*/
public int getHeight() {
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index a962212..94a9f65 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -55,7 +55,7 @@
private static final String LOGTAG = "MenuBuilder";
/** The number of different menu types */
- public static final int NUM_TYPES = 4;
+ public static final int NUM_TYPES = 5;
/** The menu type that represents the icon menu view */
public static final int TYPE_ICON = 0;
/** The menu type that represents the expanded menu view */
@@ -66,20 +66,24 @@
* have an ItemView.
*/
public static final int TYPE_DIALOG = 2;
-
/**
* The menu type that represents a button in the application's action bar.
*/
public static final int TYPE_ACTION_BUTTON = 3;
+ /**
+ * The menu type that represents a menu popup.
+ */
+ public static final int TYPE_POPUP = 4;
private static final String VIEWS_TAG = "android:views";
-
+
// Order must be the same order as the TYPE_*
static final int THEME_RES_FOR_TYPE[] = new int[] {
com.android.internal.R.style.Theme_IconMenu,
com.android.internal.R.style.Theme_ExpandedMenu,
0,
0,
+ 0,
};
// Order must be the same order as the TYPE_*
@@ -88,6 +92,7 @@
com.android.internal.R.layout.expanded_menu_layout,
0,
com.android.internal.R.layout.action_menu_layout,
+ 0,
};
// Order must be the same order as the TYPE_*
@@ -96,6 +101,7 @@
com.android.internal.R.layout.list_menu_item_layout,
com.android.internal.R.layout.list_menu_item_layout,
com.android.internal.R.layout.action_menu_item_layout,
+ com.android.internal.R.layout.list_menu_item_layout,
};
private static final int[] sCategoryToOrder = new int[] {
@@ -1251,7 +1257,19 @@
}
public View getView(int position, View convertView, ViewGroup parent) {
- return ((MenuItemImpl) getItem(position)).getItemView(mMenuType, parent);
+ if (convertView != null) {
+ MenuView.ItemView itemView = (MenuView.ItemView) convertView;
+ itemView.getItemData().setItemView(mMenuType, null);
+
+ MenuItemImpl item = (MenuItemImpl) getItem(position);
+ itemView.initialize(item, mMenuType);
+ item.setItemView(mMenuType, itemView);
+ return convertView;
+ } else {
+ MenuItemImpl item = (MenuItemImpl) getItem(position);
+ item.setItemView(mMenuType, null);
+ return item.getItemView(mMenuType, parent);
+ }
}
}
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 5fe75be..fecbd77 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -583,6 +583,10 @@
return (View) mItemViews[menuType].get();
}
+ void setItemView(int menuType, ItemView view) {
+ mItemViews[menuType] = new WeakReference<ItemView>(view);
+ }
+
/**
* Create and initializes a menu item view that implements {@link MenuView.ItemView}.
* @param menuType The type of menu to get a View for (must be one of
@@ -631,7 +635,10 @@
* @return Whether the given menu type should show icons for menu items.
*/
public boolean shouldShowIcon(int menuType) {
- return menuType == MenuBuilder.TYPE_ICON || mMenu.getOptionalIconsVisible();
+ return menuType == MenuBuilder.TYPE_ICON ||
+ menuType == MenuBuilder.TYPE_ACTION_BUTTON ||
+ menuType == MenuBuilder.TYPE_POPUP ||
+ mMenu.getOptionalIconsVisible();
}
public boolean isActionButton() {
diff --git a/core/java/com/android/internal/view/menu/MenuPopupHelper.java b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
new file mode 100644
index 0000000..751ecda
--- /dev/null
+++ b/core/java/com/android/internal/view/menu/MenuPopupHelper.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2010 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.internal.view.menu;
+
+import com.android.internal.view.menu.MenuBuilder.MenuAdapter;
+
+import android.content.Context;
+import android.util.DisplayMetrics;
+import android.view.View;
+import android.view.View.MeasureSpec;
+import android.widget.AdapterView;
+import android.widget.ListPopupWindow;
+
+/**
+ * @hide
+ */
+public class MenuPopupHelper implements AdapterView.OnItemClickListener {
+ private static final String TAG = "MenuPopupHelper";
+
+ private Context mContext;
+ private ListPopupWindow mPopup;
+ private SubMenuBuilder mSubMenu;
+ private int mPopupMaxWidth;
+
+ public MenuPopupHelper(Context context, SubMenuBuilder subMenu) {
+ mContext = context;
+ mSubMenu = subMenu;
+
+ final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+ mPopupMaxWidth = metrics.widthPixels / 2;
+ }
+
+ public void show() {
+ // TODO Use a style from the theme here
+ mPopup = new ListPopupWindow(mContext, null, 0,
+ com.android.internal.R.style.Widget_Spinner);
+ mPopup.setOnItemClickListener(this);
+
+ final MenuAdapter adapter = mSubMenu.getMenuAdapter(MenuBuilder.TYPE_POPUP);
+ mPopup.setAdapter(adapter);
+ mPopup.setModal(true);
+
+ final MenuItemImpl itemImpl = (MenuItemImpl) mSubMenu.getItem();
+ final View anchorView = itemImpl.getItemView(MenuBuilder.TYPE_ACTION_BUTTON, null);
+ mPopup.setAnchorView(anchorView);
+
+ mPopup.setContentWidth(Math.min(measureContentWidth(adapter), mPopupMaxWidth));
+ mPopup.show();
+ }
+
+ public void dismiss() {
+ mPopup.dismiss();
+ mPopup = null;
+ }
+
+ public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
+ mSubMenu.performItemAction(mSubMenu.getItem(position), 0);
+ mPopup.dismiss();
+ }
+
+ private int measureContentWidth(MenuAdapter adapter) {
+ // Menus don't tend to be long, so this is more sane than it looks.
+ int width = 0;
+ View itemView = null;
+ final int widthMeasureSpec =
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ final int heightMeasureSpec =
+ MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
+ final int count = adapter.getCount();
+ for (int i = 0; i < count; i++) {
+ itemView = adapter.getView(i, itemView, null);
+ itemView.measure(widthMeasureSpec, heightMeasureSpec);
+ width = Math.max(width, itemView.getMeasuredWidth());
+ }
+ return width;
+ }
+}