diff options
18 files changed, 544 insertions, 411 deletions
diff --git a/api/current.xml b/api/current.xml index 8a6b09a6dda4..5ad31db516fe 100644 --- a/api/current.xml +++ b/api/current.xml @@ -2088,6 +2088,28 @@ visibility="public" > </field> +<field name="actionButtonStyle" + type="int" + transient="false" + volatile="false" + value="16843545" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> +<field name="actionDropDownStyle" + type="int" + transient="false" + volatile="false" + value="16843544" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="activityCloseEnterAnimation" type="int" transient="false" @@ -3683,6 +3705,17 @@ visibility="public" > </field> +<field name="dropDownSpinnerStyle" + type="int" + transient="false" + volatile="false" + value="16843543" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="dropDownVerticalOffset" type="int" transient="false" @@ -8556,6 +8589,17 @@ visibility="public" > </field> +<field name="showAsAction" + type="int" + transient="false" + volatile="false" + value="16843546" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="showDefault" type="int" transient="false" @@ -16531,6 +16575,17 @@ visibility="public" > </field> +<field name="Widget_ActionButton" + type="int" + transient="false" + volatile="false" + value="16973971" + static="true" + final="true" + deprecated="not deprecated" + visibility="public" +> +</field> <field name="Widget_AutoCompleteTextView" type="int" transient="false" @@ -19480,19 +19535,6 @@ <parameter name="mask" type="int"> </parameter> </method> -<method name="setDividerDrawable" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="d" type="android.graphics.drawable.Drawable"> -</parameter> -</method> <method name="setDropdownNavigationMode" return="void" abstract="true" @@ -19534,17 +19576,6 @@ <parameter name="title" type="java.lang.CharSequence"> </parameter> </method> -<method name="updateActionMenu" - return="void" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -</method> <field name="DISPLAY_HIDE_HOME" type="int" transient="false" @@ -19619,19 +19650,6 @@ deprecated="not deprecated" visibility="public" > -<method name="onActionItemClicked" - return="boolean" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="item" type="android.view.MenuItem"> -</parameter> -</method> <method name="onContextItemClicked" return="boolean" abstract="true" @@ -19647,19 +19665,6 @@ <parameter name="item" type="android.view.MenuItem"> </parameter> </method> -<method name="onCreateActionMenu" - return="boolean" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="menu" type="android.view.Menu"> -</parameter> -</method> <method name="onCreateContextMode" return="boolean" abstract="true" @@ -19705,19 +19710,6 @@ <parameter name="menu" type="android.view.Menu"> </parameter> </method> -<method name="onUpdateActionMenu" - return="boolean" - abstract="true" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="menu" type="android.view.Menu"> -</parameter> -</method> </interface> <class name="ActionBar.SimpleCallback" extends="java.lang.Object" @@ -19737,19 +19729,6 @@ visibility="public" > </constructor> -<method name="onActionItemClicked" - return="boolean" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="item" type="android.view.MenuItem"> -</parameter> -</method> <method name="onContextItemClicked" return="boolean" abstract="false" @@ -19765,19 +19744,6 @@ <parameter name="item" type="android.view.MenuItem"> </parameter> </method> -<method name="onCreateActionMenu" - return="boolean" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="menu" type="android.view.Menu"> -</parameter> -</method> <method name="onCreateContextMode" return="boolean" abstract="false" @@ -19823,19 +19789,6 @@ <parameter name="menu" type="android.view.Menu"> </parameter> </method> -<method name="onUpdateActionMenu" - return="boolean" - abstract="false" - native="false" - synchronized="false" - static="false" - final="false" - deprecated="not deprecated" - visibility="public" -> -<parameter name="menu" type="android.view.Menu"> -</parameter> -</method> </class> <class name="Activity" extends="android.view.ContextThemeWrapper" @@ -36198,6 +36151,19 @@ visibility="public" > </method> +<method name="onCancelled" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="data" type="D"> +</parameter> +</method> </class> <class name="BroadcastReceiver" extends="java.lang.Object" @@ -41751,6 +41717,19 @@ visibility="public" > </method> +<method name="onCancelled" + return="void" + abstract="false" + native="false" + synchronized="false" + static="false" + final="false" + deprecated="not deprecated" + visibility="public" +> +<parameter name="cursor" type="android.database.Cursor"> +</parameter> +</method> <method name="setProjection" return="void" abstract="false" diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java index 8df3f257f7c9..4387361da041 100644 --- a/core/java/android/app/ActionBar.java +++ b/core/java/android/app/ActionBar.java @@ -20,7 +20,6 @@ import android.graphics.drawable.Drawable; import android.view.Menu; import android.view.MenuItem; import android.view.View; -import android.widget.AdapterView; import android.widget.SpinnerAdapter; /** @@ -154,13 +153,6 @@ public abstract class ActionBar { public abstract void setBackgroundDrawable(Drawable d); /** - * Set a drawable to use as a divider between sections of the ActionBar. - * - * @param d Divider drawable - */ - public abstract void setDividerDrawable(Drawable d); - - /** * @return The current custom navigation view. */ public abstract View getCustomNavigationView(); @@ -207,53 +199,10 @@ public abstract class ActionBar { public abstract int getDisplayOptions(); /** - * Request an update of the items in the action menu. - * This will result in a call to Callback.onUpdateActionMenu(Menu) - * and the ActionBar will update based on any changes made there. - */ - public abstract void updateActionMenu(); - - /** * Callback interface for ActionBar events. */ public interface Callback { /** - * Initialize the always-visible contents of the action bar. - * You should place your menu items into <var>menu</var>. - * - * <p>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 ed3705852057..382f1bd8a8f8 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 3ed345e4aa24..39668474f985 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<ActionMenu> mContextMenus; private Callback mCallback; - - private final ArrayList<ActionView> mActions = new ArrayList<ActionView>(); - 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<ActionMenu>(); } - 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) { - 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<ActionView> 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<ActionView> detachedViews = new ArrayList<ActionView>(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<ActionView> 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 a37d83dd36db..3335e85436c8 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 81294922007f..05ae79395930 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 000000000000..f0d9f6065e8d --- /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 000000000000..596e3de6c65a --- /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<MenuItemImpl> 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 beb57ba2340c..bbf7c689e298 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<MenuItemImpl> itemsToShow = mMenu.getVisibleItems(); + final ArrayList<MenuItemImpl> 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 228d5d09b0ab..a9622128d6e9 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<MenuItemImpl> mActionItems; + /** + * Contains items that should NOT appear in the Action Bar, if present. + */ + private ArrayList<MenuItemImpl> 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<MenuItemImpl>(); mIsVisibleItemsStale = true; + mActionItems = new ArrayList<MenuItemImpl>(); + mNonActionItems = new ArrayList<MenuItemImpl>(); + 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<MenuItemImpl> 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<MenuItemImpl> 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<MenuItemImpl> getActionItems() { + flagActionItems(); + return mActionItems; + } + + ArrayList<MenuItemImpl> 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 9b582057fa7c..dc1e81f04b1d 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 000000000000..3f06251e7901 --- /dev/null +++ b/core/res/res/layout/action_menu_item_layout.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<com.android.internal.view.menu.ActionMenuItemView xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + /> 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 000000000000..18d5531a81d5 --- /dev/null +++ b/core/res/res/layout/action_menu_layout.xml @@ -0,0 +1,20 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- 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. +--> + +<com.android.internal.view.menu.ActionMenuView + xmlns:android="http://schemas.android.com/apk/res/android" + android:layout_width="wrap_content" + android:layout_height="wrap_content" /> diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml index d3e66ee1150a..d98457507984 100755 --- a/core/res/res/values/attrs.xml +++ b/core/res/res/values/attrs.xml @@ -397,8 +397,12 @@ <attr name="horizontalScrollViewStyle" format="reference" /> <!-- Default Spinner style. --> <attr name="spinnerStyle" format="reference" /> - <!-- Dropdown Spinner style. --> + <!-- Default dropdown Spinner style. --> <attr name="dropDownSpinnerStyle" format="reference" /> + <!-- Default ActionBar dropdown style. --> + <attr name="actionDropDownStyle" format="reference" /> + <!-- Default action button style. --> + <attr name="actionButtonStyle" format="reference" /> <!-- Default Star style. --> <attr name="starStyle" format="reference" /> <!-- Default TabWidget style. --> @@ -3287,6 +3291,13 @@ called when the item is clicked. --> <attr name="onClick" /> + <!-- How this item should display in the Action Bar, if present. --> + <attr name="showAsAction" format="enum"> + <enum name="never" value="0" /> + <enum name="ifRoom" value="1" /> + <enum name="always" value="2" /> + </attr> + </declare-styleable> <!-- **************************************************************** --> diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml index 8b1c9d46f669..3dba1a07c5a4 100644 --- a/core/res/res/values/public.xml +++ b/core/res/res/values/public.xml @@ -1294,10 +1294,15 @@ <public type="attr" name="hardwareAccelerated" /> <public type="attr" name="measureWithLargestChild" /> <public type="attr" name="animateFirstView" /> + <public type="attr" name="dropDownSpinnerStyle" /> + <public type="attr" name="actionDropDownStyle" /> + <public type="attr" name="actionButtonStyle" /> + <public type="attr" name="showAsAction" /> <public type="id" name="home" /> <public type="style" name="Theme.WithActionBar" /> <public type="style" name="Widget.Spinner.DropDown" /> + <public type="style" name="Widget.ActionButton" /> </resources> diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml index 4f74413f40f3..5ed26d3e2b44 100644 --- a/core/res/res/values/styles.xml +++ b/core/res/res/values/styles.xml @@ -873,4 +873,7 @@ <item name="android:displayOptions">useLogo</item> <item name="android:divider">@android:drawable/action_bar_divider</item> </style> + + <style name="Widget.ActionButton"> + </style> </resources> diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml index bc5f610076d3..1f9f1367d2b4 100644 --- a/core/res/res/values/themes.xml +++ b/core/res/res/values/themes.xml @@ -170,6 +170,8 @@ <item name="horizontalScrollViewStyle">@android:style/Widget.HorizontalScrollView</item> <item name="spinnerStyle">@android:style/Widget.Spinner</item> <item name="dropDownSpinnerStyle">@android:style/Widget.Spinner.DropDown</item> + <item name="actionDropDownStyle">@android:style/Widget.Spinner.DropDown</item> + <item name="actionButtonStyle">@android:style/Widget.ActionButton</item> <item name="starStyle">@android:style/Widget.CompoundButton.Star</item> <item name="tabWidgetStyle">@android:style/Widget.TabWidget</item> <item name="textViewStyle">@android:style/Widget.TextView</item> diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java index 1c78a01d1c79..eea855d6f179 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. * <p> @@ -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); } } } |