diff options
-rw-r--r-- | api/current.xml | 13 | ||||
-rw-r--r-- | core/java/android/widget/ListPopupWindow.java | 15 | ||||
-rw-r--r-- | core/java/com/android/internal/view/menu/MenuBuilder.java | 26 | ||||
-rw-r--r-- | core/java/com/android/internal/view/menu/MenuItemImpl.java | 9 | ||||
-rw-r--r-- | core/java/com/android/internal/view/menu/MenuPopupHelper.java | 91 | ||||
-rw-r--r-- | policy/src/com/android/internal/policy/impl/PhoneWindow.java | 26 |
6 files changed, 169 insertions, 11 deletions
diff --git a/api/current.xml b/api/current.xml index d093416..086a87a 100644 --- a/api/current.xml +++ b/api/current.xml @@ -214120,6 +214120,19 @@ <parameter name="d" type="android.graphics.drawable.Drawable"> </parameter> </method> +<method name="setContentWidth" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="width" type="int"> +</parameter> +</method> <method name="setHeight" return="void" abstract="false" 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 @@ public class ListPopupWindow { 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 @@ public class ListPopupWindow { } /** + * 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 @@ public class MenuBuilder implements Menu { 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 @@ public class MenuBuilder implements Menu { * 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 @@ public class MenuBuilder implements Menu { 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 @@ public class MenuBuilder implements Menu { 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 class MenuBuilder implements Menu { } 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 @@ public final class MenuItemImpl implements MenuItem { 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 @@ public final class MenuItemImpl implements MenuItem { * @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; + } +} diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index 5c56d3c..879679f 100644 --- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java +++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java @@ -27,6 +27,7 @@ import com.android.internal.view.RootViewSurfaceTaker; import com.android.internal.view.menu.ContextMenuBuilder; import com.android.internal.view.menu.MenuBuilder; import com.android.internal.view.menu.MenuDialogHelper; +import com.android.internal.view.menu.MenuPopupHelper; import com.android.internal.view.menu.MenuView; import com.android.internal.view.menu.SubMenuBuilder; import com.android.internal.widget.ActionBarView; @@ -77,9 +78,12 @@ import android.view.animation.AnimationUtils; import android.view.inputmethod.InputMethodManager; import android.widget.FrameLayout; import android.widget.ImageView; +import android.widget.ListPopupWindow; import android.widget.ProgressBar; import android.widget.TextView; +import java.lang.ref.WeakReference; + /** * Android-specific Window. * <p> @@ -96,7 +100,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * Simple callback used by the context menu and its submenus. The options * menu submenus do not use this (their behavior is more complex). */ - ContextMenuCallback mContextMenuCallback = new ContextMenuCallback(FEATURE_CONTEXT_MENU); + DialogMenuCallback mContextMenuCallback = new DialogMenuCallback(FEATURE_CONTEXT_MENU); // This is the top-level view of the window, containing the window decor. private DecorView mDecor; @@ -808,8 +812,20 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { return true; } - // The window manager will give us a valid window token - new MenuDialogHelper(subMenu).show(null); + final Menu parentMenu = subMenu.getRootMenu(); + final PanelFeatureState panel = findMenuPanel(parentMenu); + + /* + * Use the panel open state to determine whether this is coming from an open panel + * or an action button. If it's an open panel we want to use MenuDialogHelper. + * If it's closed we want to grab the relevant view and create a popup anchored to it. + */ + if (panel.isOpen) { + // The window manager will give us a valid window token + new MenuDialogHelper(subMenu).show(null); + } else { + new MenuPopupHelper(getContext(), subMenu).show(); + } return true; } @@ -2797,11 +2813,11 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback { * <li> Calls back to the callback's onMenuItemSelected when an item is * selected. */ - private final class ContextMenuCallback implements MenuBuilder.Callback { + private final class DialogMenuCallback implements MenuBuilder.Callback { private int mFeatureId; private MenuDialogHelper mSubMenuHelper; - public ContextMenuCallback(int featureId) { + public DialogMenuCallback(int featureId) { mFeatureId = featureId; } |