menu.
- *
- * This is only called once, the first time the action bar is displayed.
- *
- * @param menu The action menu in which to place your items.
- * @return You must return true for actions to be displayed;
- * if you return false they will not be shown.
- *
- * @see #onActionItemClicked(MenuItem)
- */
- public boolean onCreateActionMenu(Menu menu);
-
- /**
- * Update the action bar. This is called in response to {@link #updateActionMenu()}
- * calls, which may be application-initiated or the result of changing fragment state.
- *
- * @return true if the action bar should update based on altered menu contents,
- * false if no changes are necessary.
- */
- public boolean onUpdateActionMenu(Menu menu);
-
- /**
- * This hook is called whenever an action item in your action bar is clicked.
- * The default implementation simply returns false to have the normal
- * processing happen (sending a message to its handler). You can use this
- * method for any items for which you would like to do processing without
- * those other facilities.
- *
- * @param item The action bar item that was selected.
- * @return boolean Return false to allow normal menu processing to proceed,
- * true to consume it here.
- */
- public boolean onActionItemClicked(MenuItem item);
-
/**
* This method is called whenever a navigation item in your action bar
* is selected.
@@ -276,18 +225,6 @@ public abstract class ActionBar {
* Extend this if you only need a subset of Callback functionality.
*/
public static class SimpleCallback implements Callback {
- public boolean onCreateActionMenu(Menu menu) {
- return false;
- }
-
- public boolean onUpdateActionMenu(Menu menu) {
- return false;
- }
-
- public boolean onActionItemClicked(MenuItem item) {
- return false;
- }
-
public boolean onCreateContextMode(int modeId, Menu menu) {
return false;
}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index ed37058520579..382f1bd8a8f84 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -936,6 +936,10 @@ public class Activity extends ContextThemeWrapper
mTitleReady = true;
onTitleChanged(getTitle(), getTitleColor());
}
+ if (mWindow != null && mWindow.hasFeature(Window.FEATURE_ACTION_BAR)) {
+ // Invalidate the action bar menu so that it can initialize properly.
+ mWindow.invalidatePanelMenu(Window.FEATURE_ACTION_BAR);
+ }
mCalled = true;
}
diff --git a/core/java/android/view/ActionBarView.java b/core/java/android/view/ActionBarView.java
index 3ed345e4aa242..39668474f985d 100644
--- a/core/java/android/view/ActionBarView.java
+++ b/core/java/android/view/ActionBarView.java
@@ -16,7 +16,10 @@
package android.view;
-import java.util.ArrayList;
+import com.android.internal.R;
+import com.android.internal.view.menu.ActionMenu;
+import com.android.internal.view.menu.ActionMenuItem;
+import com.android.internal.view.menu.MenuBuilder;
import android.app.ActionBar;
import android.app.Activity;
@@ -37,10 +40,6 @@ import android.widget.Spinner;
import android.widget.SpinnerAdapter;
import android.widget.TextView;
-import com.android.internal.R;
-import com.android.internal.view.menu.ActionMenu;
-import com.android.internal.view.menu.ActionMenuItem;
-
/**
* @hide
*/
@@ -75,7 +74,6 @@ public class ActionBarView extends ViewGroup {
private CharSequence mSubtitle;
private Drawable mIcon;
private Drawable mLogo;
- private Drawable mDivider;
private ImageView mIconView;
private ImageView mLogoView;
@@ -86,25 +84,14 @@ public class ActionBarView extends ViewGroup {
private boolean mShowMenu;
+ private MenuBuilder mOptionsMenu;
+ private View mMenuView;
+
private ActionMenuItem mLogoNavItem;
- private ActionMenu mActionMenu;
- private ActionMenu mOptionsMenu;
private SparseArray mContextMenus;
private Callback mCallback;
-
- private final ArrayList mActions = new ArrayList();
- private final OnClickListener mActionClickHandler = new OnClickListener() {
- public void onClick(View v) {
- ActionView av = (ActionView) v;
- ActionMenuItem item = (ActionMenuItem) av.menuItem;
-
- if (mCallback == null || !mCallback.onActionItemClicked(item)) {
- item.invoke();
- }
- }
- };
private final AdapterView.OnItemSelectedListener mNavItemSelectedListener =
new AdapterView.OnItemSelectedListener() {
@@ -151,7 +138,6 @@ public class ActionBarView extends ViewGroup {
if (mIcon == null) {
mIcon = info.loadIcon(pm);
}
- mDivider = a.getDrawable(R.styleable.ActionBar_divider);
Drawable background = a.getDrawable(R.styleable.ActionBar_background);
if (background != null) {
@@ -178,8 +164,10 @@ public class ActionBarView extends ViewGroup {
mLogoNavItem = new ActionMenuItem(context, 0, android.R.id.home, 0, 0, mTitle);
mHomeClickListener = new OnClickListener() {
public void onClick(View v) {
- if (mCallback != null) {
- mCallback.onActionItemClicked(mLogoNavItem);
+ Context context = getContext();
+ if (context instanceof Activity) {
+ Activity activity = (Activity) context;
+ activity.onOptionsItemSelected(mLogoNavItem);
}
}
};
@@ -188,31 +176,22 @@ public class ActionBarView extends ViewGroup {
mContextMenus = new SparseArray();
}
- private boolean initOptionsMenu() {
- final Context context = getContext();
- if (!(context instanceof Activity)) {
- return false;
- }
-
- final Activity activity = (Activity) context;
- ActionMenu optionsMenu = new ActionMenu(context);
- if (activity.onCreateOptionsMenu(optionsMenu)) {
- mOptionsMenu = optionsMenu;
- return true;
- }
-
- return false;
+ public void setCallback(Callback callback) {
+ mCallback = callback;
}
- public void setCallback(Callback callback) {
- final Context context = getContext();
- mCallback = callback;
-
- ActionMenu actionMenu = new ActionMenu(context);
- if (callback.onCreateActionMenu(actionMenu)) {
- mActionMenu = actionMenu;
- performUpdateActionMenu();
+ public void setMenu(Menu menu) {
+ MenuBuilder builder = (MenuBuilder) menu;
+ mOptionsMenu = builder;
+ if (mMenuView != null) {
+ removeView(mMenuView);
}
+ final View menuView = builder.getMenuView(MenuBuilder.TYPE_ACTION_BUTTON, null);
+ final LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
+ LayoutParams.MATCH_PARENT);
+ menuView.setLayoutParams(layoutParams);
+ addView(menuView);
+ mMenuView = menuView;
}
public void setCustomNavigationView(View view) {
@@ -222,10 +201,6 @@ public class ActionBarView extends ViewGroup {
}
}
- public void setDividerDrawable(Drawable d) {
- mDivider = d;
- }
-
public CharSequence getTitle() {
return mTitle;
}
@@ -301,9 +276,13 @@ public class ActionBarView extends ViewGroup {
mSpinner = new Spinner(mContext, null,
com.android.internal.R.attr.dropDownSpinnerStyle);
mSpinner.setOnItemSelectedListener(mNavItemSelectedListener);
+ mSpinner.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
+ LayoutParams.WRAP_CONTENT));
addView(mSpinner);
break;
case ActionBar.NAVIGATION_MODE_CUSTOM:
+ mCustomNavView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
+ LayoutParams.WRAP_CONTENT));
addView(mCustomNavView);
break;
}
@@ -328,18 +307,6 @@ public class ActionBarView extends ViewGroup {
return mDisplayOptions;
}
- private ActionView findActionViewForItem(MenuItem item) {
- final ArrayList actions = mActions;
- final int actionCount = actions.size();
- for (int i = 0; i < actionCount; i++) {
- ActionView av = actions.get(i);
- if (av.menuItem.equals(item)) {
- return av;
- }
- }
- return null;
- }
-
public void setContextMode(int mode) {
Callback callback = mCallback;
if (callback == null) {
@@ -368,92 +335,6 @@ public class ActionBarView extends ViewGroup {
// TODO Turn off context mode; go back to normal.
}
- public void updateActionMenu() {
- final ActionMenu menu = mActionMenu;
- if (menu == null || mCallback == null || !mCallback.onUpdateActionMenu(menu)) {
- return;
- }
- performUpdateActionMenu();
- }
-
- private void performUpdateActionMenu() {
- final ActionMenu menu = mActionMenu;
- if (menu == null) {
- return;
- }
- final Context context = getContext();
-
- int childCount = getChildCount();
- int childIndex = 0;
- while (childIndex < childCount) {
- View v = getChildAt(childIndex);
- if (v instanceof ActionView) {
- detachViewFromParent(childIndex);
- childCount--;
- } else {
- childIndex++;
- }
- }
-
- ArrayList detachedViews = new ArrayList(mActions);
- final int itemCount = menu.size();
- for (int i = 0; i < itemCount; i++) {
- final MenuItem item = menu.getItem(i);
-
- boolean newView = false;
- ActionView actionView = findActionViewForItem(item);
- if (actionView == null) {
- actionView = new ActionView(context);
- newView = true;
- }
- actionView.actionId = item.getItemId();
- actionView.menuItem = item;
- actionView.actionLabel = item.getTitle();
- actionView.setAdjustViewBounds(true);
- actionView.setImageDrawable(item.getIcon());
- actionView.setFocusable(true);
- actionView.setOnClickListener(mActionClickHandler);
-
- LayoutParams layoutParams = new LayoutParams(LayoutParams.WRAP_CONTENT,
- LayoutParams.MATCH_PARENT, LayoutParams.ITEM_TYPE_ACTION);
- actionView.setLayoutParams(layoutParams);
-
- if (newView) {
- addView(actionView);
- mActions.add(actionView);
- } else {
- attachViewToParent(actionView, -1, layoutParams);
- detachedViews.remove(actionView);
- actionView.invalidate();
- }
- }
-
- final int detachedCount = detachedViews.size();
- for (int i = 0; i < detachedCount; i++) {
- removeDetachedView(detachedViews.get(i), false);
- }
-
- requestLayout();
- }
-
- public void addAction(int id, Drawable icon, CharSequence label, OnActionListener listener) {
- ActionView actionView = new ActionView(getContext());
- actionView.actionId = id;
- actionView.actionLabel = label;
- actionView.actionListener = listener;
- actionView.setAdjustViewBounds(true);
- actionView.setImageDrawable(icon);
- actionView.setOnClickListener(mActionClickHandler);
-
- actionView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
- LayoutParams.MATCH_PARENT, LayoutParams.ITEM_TYPE_ACTION));
-
- addView(actionView);
- mActions.add(actionView);
-
- requestLayout();
- }
-
@Override
protected void onFinishInflate() {
super.onFinishInflate();
@@ -463,7 +344,7 @@ public class ActionBarView extends ViewGroup {
mLogoView = new ImageView(getContext());
mLogoView.setAdjustViewBounds(true);
mLogoView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
- LayoutParams.MATCH_PARENT, LayoutParams.ITEM_TYPE_ICON));
+ LayoutParams.MATCH_PARENT));
mLogoView.setImageDrawable(mLogo);
mLogoView.setClickable(true);
mLogoView.setFocusable(true);
@@ -473,7 +354,7 @@ public class ActionBarView extends ViewGroup {
mIconView = new ImageView(getContext());
mIconView.setAdjustViewBounds(true);
mIconView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
- LayoutParams.MATCH_PARENT, LayoutParams.ITEM_TYPE_ICON));
+ LayoutParams.MATCH_PARENT));
mIconView.setImageDrawable(mIcon);
mIconView.setClickable(true);
mIconView.setFocusable(true);
@@ -508,8 +389,8 @@ public class ActionBarView extends ViewGroup {
private void initTitle() {
LayoutInflater inflater = LayoutInflater.from(getContext());
mTitleView = (TextView) inflater.inflate(R.layout.action_bar_title_item, null);
- mTitleView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
- LayoutParams.WRAP_CONTENT, LayoutParams.ITEM_TYPE_TITLE));
+ mTitleView.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT,
+ LayoutParams.WRAP_CONTENT));
if (mTitle != null) {
mTitleView.setText(mTitle);
}
@@ -542,12 +423,9 @@ public class ActionBarView extends ViewGroup {
if (mIconView != null && mIconView.getVisibility() != GONE) {
availableWidth = measureChildView(mIconView, availableWidth, childSpecHeight, mSpacing);
}
-
- final ArrayList actions = mActions;
- final int actionCount = actions.size();
- for (int i = 0; i < actionCount; i++) {
- ActionView action = actions.get(i);
- availableWidth = measureChildView(action, availableWidth,
+
+ if (mMenuView != null) {
+ availableWidth = measureChildView(mMenuView, availableWidth,
childSpecHeight, mActionSpacing);
}
@@ -619,10 +497,9 @@ public class ActionBarView extends ViewGroup {
x = r - l - getPaddingRight();
- final int count = mActions.size();
- for (int i = count - 1; i >= 0; i--) {
- ActionView action = mActions.get(i);
- x -= (positionChildInverse(action, x, y, contentHeight) + mActionSpacing);
+
+ if (mMenuView != null) {
+ x -= positionChildInverse(mMenuView, x, y, contentHeight) + mActionSpacing;
}
}
@@ -645,58 +522,4 @@ public class ActionBarView extends ViewGroup {
return childWidth;
}
-
- @Override
- public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
- return new ViewGroup.LayoutParams(getContext(), attrs);
- }
-
- @Override
- protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
- return p != null && p instanceof LayoutParams;
- }
-
- private static class LayoutParams extends ViewGroup.LayoutParams {
- static final int ITEM_TYPE_UNKNOWN = -1;
- static final int ITEM_TYPE_ICON = 0;
- static final int ITEM_TYPE_TITLE = 1;
- static final int ITEM_TYPE_CUSTOM_NAV = 2;
- static final int ITEM_TYPE_ACTION = 3;
- static final int ITEM_TYPE_MORE = 4;
-
- int type = ITEM_TYPE_UNKNOWN;
-
- public LayoutParams(Context c, AttributeSet attrs) {
- super(c, attrs);
- }
-
- public LayoutParams(int width, int height) {
- super(width, height);
- }
-
- public LayoutParams(int width, int height, int type) {
- this(width, height);
- this.type = type;
- }
-
-
- public LayoutParams(ViewGroup.LayoutParams source) {
- super(source);
- }
- }
-
- public interface OnActionListener {
- void onAction(int id);
- }
-
- private static class ActionView extends ImageView {
- int actionId;
- CharSequence actionLabel;
- OnActionListener actionListener;
- MenuItem menuItem;
-
- public ActionView(Context context) {
- super(context);
- }
- }
}
diff --git a/core/java/android/view/MenuInflater.java b/core/java/android/view/MenuInflater.java
index a37d83dd36dbe..3335e85436c8d 100644
--- a/core/java/android/view/MenuInflater.java
+++ b/core/java/android/view/MenuInflater.java
@@ -241,6 +241,14 @@ public class MenuInflater {
private boolean itemVisible;
private boolean itemEnabled;
+ /**
+ * Sync to attrs.xml enum:
+ * - 0: never
+ * - 1: ifRoom
+ * - 2: always
+ */
+ private int itemShowAsAction;
+
private String itemListenerMethodName;
private static final int defaultGroupId = NO_ID;
@@ -314,6 +322,7 @@ public class MenuInflater {
itemChecked = a.getBoolean(com.android.internal.R.styleable.MenuItem_checked, defaultItemChecked);
itemVisible = a.getBoolean(com.android.internal.R.styleable.MenuItem_visible, groupVisible);
itemEnabled = a.getBoolean(com.android.internal.R.styleable.MenuItem_enabled, groupEnabled);
+ itemShowAsAction = a.getInt(com.android.internal.R.styleable.MenuItem_showAsAction, 0);
itemListenerMethodName = a.getString(com.android.internal.R.styleable.MenuItem_onClick);
a.recycle();
@@ -344,8 +353,12 @@ public class MenuInflater {
new InflatedOnMenuItemClickListener(mContext, itemListenerMethodName));
}
- if (itemCheckable >= 2 && item instanceof MenuItemImpl) {
- ((MenuItemImpl) item).setExclusiveCheckable(true);
+ if (item instanceof MenuItemImpl) {
+ MenuItemImpl impl = (MenuItemImpl) item;
+ if (itemCheckable >= 2) {
+ impl.setExclusiveCheckable(true);
+ }
+ impl.setShowAsAction(itemShowAsAction);
}
}
diff --git a/core/java/com/android/internal/app/SplitActionBar.java b/core/java/com/android/internal/app/SplitActionBar.java
index 81294922007f0..05ae793959305 100644
--- a/core/java/com/android/internal/app/SplitActionBar.java
+++ b/core/java/com/android/internal/app/SplitActionBar.java
@@ -83,10 +83,6 @@ public class SplitActionBar extends ActionBar {
mActionView.setBackgroundDrawable(d);
}
- public void setDividerDrawable(Drawable d) {
- mActionView.setDividerDrawable(d);
- }
-
public View getCustomNavigationView() {
return mActionView.getCustomNavigationView();
}
@@ -106,9 +102,4 @@ public class SplitActionBar extends ActionBar {
public int getDisplayOptions() {
return mActionView.getDisplayOptions();
}
-
- public void updateActionMenu() {
- mActionView.updateActionMenu();
- }
-
}
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItemView.java b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
new file mode 100644
index 0000000000000..f0d9f6065e8d9
--- /dev/null
+++ b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
@@ -0,0 +1,112 @@
+/*
+ * 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 android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.view.SoundEffectConstants;
+import android.view.View;
+import android.widget.ImageButton;
+
+/**
+ * @hide
+ */
+public class ActionMenuItemView extends ImageButton implements MenuView.ItemView {
+ private static final String TAG = "ActionMenuItemView";
+
+ private MenuItemImpl mItemData;
+ private CharSequence mTitle;
+ private MenuBuilder.ItemInvoker mItemInvoker;
+
+ public ActionMenuItemView(Context context) {
+ this(context, null);
+ }
+
+ public ActionMenuItemView(Context context, AttributeSet attrs) {
+ this(context, attrs, com.android.internal.R.attr.actionButtonStyle);
+ }
+
+ public ActionMenuItemView(Context context, AttributeSet attrs, int defStyle) {
+ super(context, attrs, defStyle);
+ }
+
+ public MenuItemImpl getItemData() {
+ return mItemData;
+ }
+
+ public void initialize(MenuItemImpl itemData, int menuType) {
+ mItemData = itemData;
+
+ setClickable(true);
+ setFocusable(true);
+ setTitle(itemData.getTitle());
+ setIcon(itemData.getIcon());
+ setId(itemData.getItemId());
+
+ setVisibility(itemData.isVisible() ? View.VISIBLE : View.GONE);
+ setEnabled(itemData.isEnabled());
+ }
+
+ @Override
+ public boolean performClick() {
+ // Let the view's listener have top priority
+ if (super.performClick()) {
+ return true;
+ }
+
+ if (mItemInvoker != null && mItemInvoker.invokeItem(mItemData)) {
+ playSoundEffect(SoundEffectConstants.CLICK);
+ return true;
+ } else {
+ return false;
+ }
+ }
+
+ public void setItemInvoker(MenuBuilder.ItemInvoker invoker) {
+ mItemInvoker = invoker;
+ }
+
+ public boolean prefersCondensedTitle() {
+ return false;
+ }
+
+ public void setCheckable(boolean checkable) {
+ // TODO Support checkable action items
+ }
+
+ public void setChecked(boolean checked) {
+ // TODO Support checkable action items
+ }
+
+ public void setIcon(Drawable icon) {
+ setImageDrawable(icon);
+ }
+
+ public void setShortcut(boolean showShortcut, char shortcutKey) {
+ // Action buttons don't show text for shortcut keys.
+ }
+
+ public void setTitle(CharSequence title) {
+ mTitle = title;
+ }
+
+ public boolean showsIcon() {
+ return true;
+ }
+
+}
diff --git a/core/java/com/android/internal/view/menu/ActionMenuView.java b/core/java/com/android/internal/view/menu/ActionMenuView.java
new file mode 100644
index 0000000000000..596e3de6c65a6
--- /dev/null
+++ b/core/java/com/android/internal/view/menu/ActionMenuView.java
@@ -0,0 +1,74 @@
+/*
+ * 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 android.content.Context;
+import android.util.AttributeSet;
+import android.widget.LinearLayout;
+
+import java.util.ArrayList;
+
+/**
+ * @hide
+ */
+public class ActionMenuView extends LinearLayout implements MenuBuilder.ItemInvoker, MenuView {
+ private static final String TAG = "ActionMenuView";
+
+ // TODO: Make this a ViewConfiguration constant.
+ private static final int MAX_ACTION_ITEMS = 3;
+
+ private MenuBuilder mMenu;
+
+ public ActionMenuView(Context context) {
+ this(context, null);
+ }
+
+ public ActionMenuView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ public boolean invokeItem(MenuItemImpl item) {
+ return mMenu.performItemAction(item, 0);
+ }
+
+ public int getWindowAnimations() {
+ return 0;
+ }
+
+ public void initialize(MenuBuilder menu, int menuType) {
+ menu.setMaxActionItems(MAX_ACTION_ITEMS);
+ mMenu = menu;
+ updateChildren(true);
+ }
+
+ public void updateChildren(boolean cleared) {
+ removeAllViews();
+
+ final ArrayList itemsToShow = mMenu.getActionItems();
+ final int itemCount = itemsToShow.size();
+
+ for (int i = 0; i < itemCount; i++) {
+ final MenuItemImpl itemData = itemsToShow.get(i);
+ addItemView((ActionMenuItemView) itemData.getItemView(MenuBuilder.TYPE_ACTION_BUTTON,
+ this));
+ }
+ }
+
+ private void addItemView(ActionMenuItemView view) {
+ view.setItemInvoker(this);
+ addView(view);
+ }
+}
diff --git a/core/java/com/android/internal/view/menu/IconMenuView.java b/core/java/com/android/internal/view/menu/IconMenuView.java
index beb57ba2340c7..bbf7c689e298a 100644
--- a/core/java/com/android/internal/view/menu/IconMenuView.java
+++ b/core/java/com/android/internal/view/menu/IconMenuView.java
@@ -337,7 +337,7 @@ public final class IconMenuView extends ViewGroup implements ItemInvoker, MenuVi
// This method does a clear refresh of children
removeAllViews();
- final ArrayList itemsToShow = mMenu.getVisibleItems();
+ final ArrayList itemsToShow = mMenu.getNonActionItems();
final int numItems = itemsToShow.size();
final int numItemsThatCanFit = mMaxItems;
// Minimum of the num that can fit and the num that we have
diff --git a/core/java/com/android/internal/view/menu/MenuBuilder.java b/core/java/com/android/internal/view/menu/MenuBuilder.java
index 228d5d09b0ab2..a9622128d6e94 100644
--- a/core/java/com/android/internal/view/menu/MenuBuilder.java
+++ b/core/java/com/android/internal/view/menu/MenuBuilder.java
@@ -27,16 +27,17 @@ import android.content.res.Resources;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.Parcelable;
+import android.util.Log;
import android.util.SparseArray;
import android.view.ContextThemeWrapper;
import android.view.KeyCharacterMap;
import android.view.KeyEvent;
+import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.SubMenu;
import android.view.View;
import android.view.ViewGroup;
-import android.view.LayoutInflater;
import android.view.ContextMenu.ContextMenuInfo;
import android.widget.AdapterView;
import android.widget.BaseAdapter;
@@ -54,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 = 3;
+ public static final int NUM_TYPES = 4;
/** 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 */
@@ -65,6 +66,11 @@ 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;
private static final String VIEWS_TAG = "android:views";
@@ -73,6 +79,7 @@ public class MenuBuilder implements Menu {
com.android.internal.R.style.Theme_IconMenu,
com.android.internal.R.style.Theme_ExpandedMenu,
0,
+ 0,
};
// Order must be the same order as the TYPE_*
@@ -80,6 +87,7 @@ public class MenuBuilder implements Menu {
com.android.internal.R.layout.icon_menu_layout,
com.android.internal.R.layout.expanded_menu_layout,
0,
+ com.android.internal.R.layout.action_menu_layout,
};
// Order must be the same order as the TYPE_*
@@ -87,6 +95,7 @@ public class MenuBuilder implements Menu {
com.android.internal.R.layout.icon_menu_item_layout,
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,
};
private static final int[] sCategoryToOrder = new int[] {
@@ -130,6 +139,24 @@ public class MenuBuilder implements Menu {
* fetched from {@link #getVisibleItems()}
*/
private boolean mIsVisibleItemsStale;
+
+ /**
+ * Contains only the items that should appear in the Action Bar, if present.
+ */
+ private ArrayList mActionItems;
+ /**
+ * Contains items that should NOT appear in the Action Bar, if present.
+ */
+ private ArrayList mNonActionItems;
+ /**
+ * The number of visible action buttons permitted in this menu
+ */
+ private int mMaxActionItems;
+ /**
+ * Whether or not the items (or any one item's action state) has changed since it was
+ * last fetched.
+ */
+ private boolean mIsActionItemsStale;
/**
* Current use case is Context Menus: As Views populate the context menu, each one has
@@ -281,6 +308,10 @@ public class MenuBuilder implements Menu {
mVisibleItems = new ArrayList();
mIsVisibleItemsStale = true;
+ mActionItems = new ArrayList();
+ mNonActionItems = new ArrayList();
+ mIsActionItemsStale = true;
+
mShortcutsVisible =
(mResources.getConfiguration().keyboard != Configuration.KEYBOARD_NOKEYS);
}
@@ -900,6 +931,7 @@ public class MenuBuilder implements Menu {
private void onItemsChanged(boolean cleared) {
if (!mPreventDispatchingItemsChanged) {
if (mIsVisibleItemsStale == false) mIsVisibleItemsStale = true;
+ if (mIsActionItemsStale == false) mIsActionItemsStale = true;
MenuType[] menuTypes = mMenuTypes;
for (int i = 0; i < NUM_TYPES; i++) {
@@ -920,6 +952,15 @@ public class MenuBuilder implements Menu {
onItemsChanged(false);
}
+ /**
+ * Called by {@link MenuItemImpl} when its action request status is changed.
+ * @param item The item that has gone through a change in action request status.
+ */
+ void onItemActionRequestChanged(MenuItemImpl item) {
+ // Notify of items being changed
+ onItemsChanged(false);
+ }
+
ArrayList getVisibleItems() {
if (!mIsVisibleItemsStale) return mVisibleItems;
@@ -934,9 +975,64 @@ public class MenuBuilder implements Menu {
}
mIsVisibleItemsStale = false;
+ mIsActionItemsStale = true;
return mVisibleItems;
}
+
+ private void flagActionItems() {
+ if (!mIsActionItemsStale) {
+ return;
+ }
+
+ final ArrayList visibleItems = getVisibleItems();
+ final int itemsSize = visibleItems.size();
+ int maxActions = mMaxActionItems;
+
+ for (int i = 0; i < itemsSize; i++) {
+ MenuItemImpl item = visibleItems.get(i);
+ if (item.requiresActionButton()) {
+ maxActions--;
+ }
+ }
+
+ // Flag as many more requested items as will fit.
+ for (int i = 0; i < itemsSize; i++) {
+ MenuItemImpl item = visibleItems.get(i);
+ if (item.requestsActionButton()) {
+ item.setIsActionButton(maxActions > 0);
+ maxActions--;
+ }
+ }
+
+ mActionItems.clear();
+ mNonActionItems.clear();
+ for (int i = 0; i < itemsSize; i++) {
+ MenuItemImpl item = visibleItems.get(i);
+ if (item.isActionButton()) {
+ mActionItems.add(item);
+ } else {
+ mNonActionItems.add(item);
+ }
+ }
+
+ mIsActionItemsStale = false;
+ }
+
+ ArrayList getActionItems() {
+ flagActionItems();
+ return mActionItems;
+ }
+
+ ArrayList getNonActionItems() {
+ flagActionItems();
+ return mNonActionItems;
+ }
+
+ void setMaxActionItems(int maxActionItems) {
+ mMaxActionItems = maxActionItems;
+ mIsActionItemsStale = true;
+ }
public void clearHeader() {
mHeaderIcon = null;
diff --git a/core/java/com/android/internal/view/menu/MenuItemImpl.java b/core/java/com/android/internal/view/menu/MenuItemImpl.java
index 9b582057fa7cd..dc1e81f04b1dc 100644
--- a/core/java/com/android/internal/view/menu/MenuItemImpl.java
+++ b/core/java/com/android/internal/view/menu/MenuItemImpl.java
@@ -74,6 +74,15 @@ public final class MenuItemImpl implements MenuItem {
private static final int EXCLUSIVE = 0x00000004;
private static final int HIDDEN = 0x00000008;
private static final int ENABLED = 0x00000010;
+ private static final int IS_ACTION = 0x00000020;
+
+ /*
+ * These should be kept in sync with attrs.xml enum constants for showAsAction
+ */
+ private static final int SHOW_AS_ACTION_NEVER = 0;
+ private static final int SHOW_AS_ACTION_IF_ROOM = 1;
+ private static final int SHOW_AS_ACTION_ALWAYS = 2;
+ private int mShowAsAction = SHOW_AS_ACTION_NEVER;
/** Used for the icon resource ID if this item does not have an icon */
static final int NO_ICON = 0;
@@ -630,4 +639,35 @@ public final class MenuItemImpl implements MenuItem {
public boolean shouldShowIcon(int menuType) {
return menuType == MenuBuilder.TYPE_ICON || mMenu.getOptionalIconsVisible();
}
+
+ public boolean isActionButton() {
+ return (mFlags & IS_ACTION) == IS_ACTION || requiresActionButton();
+ }
+
+ public boolean requestsActionButton() {
+ return mShowAsAction == SHOW_AS_ACTION_IF_ROOM;
+ }
+
+ public boolean requiresActionButton() {
+ return mShowAsAction == SHOW_AS_ACTION_ALWAYS;
+ }
+
+ public void setIsActionButton(boolean isActionButton) {
+ if (isActionButton) {
+ mFlags |= IS_ACTION;
+ } else {
+ mFlags &= ~IS_ACTION;
+ }
+ }
+
+ /**
+ * Used by MenuInflater to set how this item should display in the presence of
+ * an Action Bar.
+ *
+ * @param actionEnum Enum flag as defined in attrs.xml/SHOW_AS_ constants.
+ */
+ public void setShowAsAction(int actionEnum) {
+ mShowAsAction = actionEnum;
+ mMenu.onItemActionRequestChanged(this);
+ }
}
diff --git a/core/res/res/layout/action_menu_item_layout.xml b/core/res/res/layout/action_menu_item_layout.xml
new file mode 100644
index 0000000000000..3f06251e79015
--- /dev/null
+++ b/core/res/res/layout/action_menu_item_layout.xml
@@ -0,0 +1,20 @@
+
+
+
+
diff --git a/core/res/res/layout/action_menu_layout.xml b/core/res/res/layout/action_menu_layout.xml
new file mode 100644
index 0000000000000..18d5531a81d5e
--- /dev/null
+++ b/core/res/res/layout/action_menu_layout.xml
@@ -0,0 +1,20 @@
+
+
+
+
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index d3e66ee1150a5..d984575079840 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -397,8 +397,12 @@
-
+
+
+
+
+
@@ -3287,6 +3291,13 @@
called when the item is clicked. -->
+
+
+
+
+
+
+
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 8b1c9d46f6699..3dba1a07c5a40 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1294,10 +1294,15 @@
+
+
+
+
+
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index 4f74413f40f3c..5ed26d3e2b440 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -873,4 +873,7 @@
- useLogo
- @android:drawable/action_bar_divider
+
+
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index bc5f610076d33..1f9f1367d2b41 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -170,6 +170,8 @@
- @android:style/Widget.HorizontalScrollView
- @android:style/Widget.Spinner
- @android:style/Widget.Spinner.DropDown
+ - @android:style/Widget.Spinner.DropDown
+ - @android:style/Widget.ActionButton
- @android:style/Widget.CompoundButton.Star
- @android:style/Widget.TabWidget
- @android:style/Widget.TextView
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 1c78a01d1c79a..eea855d6f1799 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -44,7 +44,6 @@ import android.graphics.drawable.Drawable;
import android.media.AudioManager;
import android.net.Uri;
import android.os.Bundle;
-import android.os.Message;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
@@ -63,7 +62,6 @@ import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.MotionEvent;
-import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.View;
import android.view.ViewGroup;
@@ -81,12 +79,6 @@ import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;
-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.MenuView;
-import com.android.internal.view.menu.SubMenuBuilder;
-
/**
* Android-specific Window.
*
@@ -307,7 +299,7 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
// Already prepared (isPrepared will be reset to false later)
if (st.isPrepared)
return true;
-
+
if ((mPreparedPanel != null) && (mPreparedPanel != st)) {
// Another Panel is prepared and possibly open, so close it
closePanel(mPreparedPanel, false);
@@ -334,7 +326,12 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
return false;
}
+
st.refreshMenuContent = false;
+
+ if (mActionBar != null) {
+ mActionBar.setMenu(st.menu);
+ }
}
// Callback and return if the callback does not want to show the menu
@@ -383,11 +380,9 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
clearMenuViews(st);
}
}
-
}
private static void clearMenuViews(PanelFeatureState st) {
-
// This can be called on config changes, so we should make sure
// the views will be reconstructed based on the new orientation, etc.
@@ -562,6 +557,16 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
st.refreshMenuContent = true;
st.refreshDecorView = true;
+
+ // Prepare the options panel if we have an action bar
+ if ((featureId == FEATURE_ACTION_BAR || featureId == FEATURE_OPTIONS_PANEL)
+ && mActionBar != null) {
+ st = getPanelState(Window.FEATURE_OPTIONS_PANEL, false);
+ if (st != null) {
+ st.isPrepared = false;
+ preparePanel(st, null);
+ }
+ }
}
/**
@@ -2295,10 +2300,8 @@ public class PhoneWindow extends Window implements MenuBuilder.Callback {
}
} else {
mActionBar = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
- if (mActionBar != null) {
- if (mActionBar.getTitle() == null) {
- mActionBar.setTitle(mTitle);
- }
+ if (mActionBar != null && mActionBar.getTitle() == null) {
+ mActionBar.setTitle(mTitle);
}
}
}