ActionBar added to framework, integrated with Activity and styles.
Added onClick attribute support to menus in MenuInflater.

Change-Id: I739771b4f249d87a0d8b15969f3d526b099067a1
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
new file mode 100644
index 0000000..e28d3d3
--- /dev/null
+++ b/core/java/android/app/ActionBar.java
@@ -0,0 +1,253 @@
+/*
+ * 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 android.app;
+
+import android.graphics.drawable.Drawable;
+import android.view.ActionBarView;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.View;
+
+/**
+ * This is the public interface to the contextual ActionBar.
+ * The ActionBar acts as a replacement for the title bar in Activities.
+ * It provides facilities for creating toolbar actions as well as
+ * methods of navigating around an application. 
+ */
+public abstract class ActionBar {
+	/**
+	 * Normal/standard navigation mode. Consists of either a logo or icon
+	 * and title text with an optional subtitle. Clicking any of these elements
+	 * will dispatch onActionItemSelected to the registered Callback with
+	 * a MenuItem with item ID android.R.id.home.
+	 */
+    public static final int NAVIGATION_MODE_NORMAL = 0;
+    
+    /**
+     * Dropdown list navigation mode. Instead of static title text this mode
+     * presents a dropdown menu for navigation within the activity.
+     */
+    public static final int NAVIGATION_MODE_DROPDOWN_LIST = 1;
+    
+    /**
+     * Tab navigation mode. Instead of static title text this mode
+     * presents a series of tabs for navigation within the activity.
+     */
+    public static final int NAVIGATION_MODE_TABS = 2;
+    
+    /**
+     * Custom navigation mode. This navigation mode is set implicitly whenever
+     * a custom navigation view is set. See {@link #setCustomNavigationView(View)}.
+     */
+    public static final int NAVIGATION_MODE_CUSTOM = 3;
+
+    /**
+     * Use logo instead of icon if available. This flag will cause appropriate
+     * navigation modes to use a wider logo in place of the standard icon.
+     */
+    public static final int DISPLAY_USE_LOGO = 0x1;
+    
+    /**
+     * Hide 'home' elements in this action bar, leaving more space for other
+     * navigation elements. This includes logo and icon.
+     */
+    public static final int DISPLAY_HIDE_HOME = 0x2;
+    
+    /**
+     * Set the callback that the ActionBar will use to handle events
+     * and populate menus.
+     * @param callback Callback to use
+     */
+    public abstract void setCallback(Callback callback);
+    
+    /**
+     * Set a custom navigation view.
+     * 
+     * Custom navigation views appear between the application icon and
+     * any action buttons and may use any space available there. Common
+     * use cases for custom navigation views might include an address bar
+     * for a browser or other navigation mechanisms that do not translate
+     * well to provided navigation modes.
+     * 
+     * Setting a non-null custom navigation view will also set the
+     * navigation mode to NAVMODE_CUSTOM.
+     * 
+     * @param view Custom navigation view to place in the ActionBar.
+     */
+    public abstract void setCustomNavigationView(View view);
+    
+    /**
+     * Set the ActionBar's title.
+     * 
+     * This is set automatically to the name of your Activity,
+     * but may be changed here.
+     * 
+     * @param title Title text
+     */
+    public abstract void setTitle(CharSequence title);
+    
+    /**
+     * Set the ActionBar's subtitle.
+     * 
+     * The subtitle is usually displayed as a second line of text
+     * under the title. Good for extended descriptions of activity state.
+     * 
+     * @param subtitle Subtitle text. 
+     */
+    public abstract void setSubtitle(CharSequence subtitle);
+    
+    /**
+     * Set the navigation mode.
+     *
+     * @param mode One of {@link #NAVIGATION_MODE_NORMAL}, {@link #NAVIGATION_MODE_DROPDOWN_LIST},
+     * {@link #NAVIGATION_MODE_TABS}, or {@link #NAVIGATION_MODE_CUSTOM}.
+     */
+    public abstract void setNavigationMode(int mode);
+    
+    /**
+     * Set display options.
+     * 
+     * @param options A combination of the bits defined by the DISPLAY_ constants
+     *                defined in ActionBar.
+     */
+    public abstract void setDisplayOptions(int options);
+    
+    /**
+     * Set the ActionBar's background.
+     * 
+     * @param d Background drawable
+     */
+    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();
+    
+    /**
+     * @return The current ActionBar title.
+     */
+    public abstract CharSequence getTitle();
+    
+    /**
+     * @return The current ActionBar subtitle.
+     */
+    public abstract CharSequence getSubtitle();
+    
+    /**
+     * @return The current navigation mode.
+     */
+    public abstract int getNavigationMode();
+    
+    /**
+     * @return The current set of display options. 
+     */
+    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 #onActionItemSelected(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 item in your action bar is selected.
+         * 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 onActionItemSelected(MenuItem item);
+
+        /*
+         * In progress
+         */
+        public boolean onCreateContextMode(int modeId, Menu menu);
+        public boolean onPrepareContextMode(int modeId, Menu menu);
+        public boolean onContextItemSelected(int modeId, MenuItem item);
+    }
+    
+    /**
+     * Simple stub implementations of ActionBar.Callback methods.
+     * 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 onActionItemSelected(MenuItem item) {
+            return false;
+        }
+        
+        public boolean onCreateContextMode(int modeId, Menu menu) {
+            return false;
+        }
+        
+        public boolean onPrepareContextMode(int modeId, Menu menu) {
+            return false;
+        }
+        
+        public boolean onContextItemSelected(int modeId, MenuItem item) {
+            return false;
+        }
+    }
+
+}
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index aa3cb69..21c6d2a 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -16,14 +16,16 @@
 
 package android.app;
 
-import com.android.internal.policy.PolicyManager;
+import java.lang.reflect.Constructor;
+import java.util.ArrayList;
+import java.util.HashMap;
 
 import android.content.ComponentCallbacks;
 import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
-import android.content.Intent;
 import android.content.IIntentSender;
+import android.content.Intent;
 import android.content.IntentSender;
 import android.content.SharedPreferences;
 import android.content.pm.ActivityInfo;
@@ -50,6 +52,7 @@
 import android.util.EventLog;
 import android.util.Log;
 import android.util.SparseArray;
+import android.view.ActionBarView;
 import android.view.ContextMenu;
 import android.view.ContextThemeWrapper;
 import android.view.InflateException;
@@ -69,10 +72,10 @@
 import android.view.ViewGroup.LayoutParams;
 import android.view.accessibility.AccessibilityEvent;
 import android.widget.AdapterView;
+import android.widget.LinearLayout;
 
-import java.lang.reflect.Constructor;
-import java.util.ArrayList;
-import java.util.HashMap;
+import com.android.internal.app.SplitActionBar;
+import com.android.internal.policy.PolicyManager;
 
 /**
  * An activity is a single, focused thing that the user can do.  Almost all
@@ -650,6 +653,7 @@
     /*package*/ boolean mWindowAdded = false;
     /*package*/ boolean mVisibleFromServer = false;
     /*package*/ boolean mVisibleFromClient = true;
+    /*package*/ ActionBar mActionBar = null;
 
     private CharSequence mTitle;
     private int mTitleColor = 0;
@@ -1793,7 +1797,19 @@
     public View findViewById(int id) {
         return getWindow().findViewById(id);
     }
-
+    
+    /**
+     * Retrieve a reference to this activity's ActionBar.
+     * 
+     * <p><em>Note:</em> The ActionBar is initialized when a content view
+     * is set. This function will return null if called before {@link #setContentView}
+     * or {@link #addContentView}.
+     * @return The Activity's ActionBar, or null if it does not have one.
+     */
+    public ActionBar getActionBar() {
+        return mActionBar;
+    }
+    
     /**
      * Finds a fragment that was identified by the given id either when inflated
      * from XML or as the container ID when added in a transaction.  This only
@@ -1805,6 +1821,27 @@
     }
     
     /**
+     * Creates a new ActionBar, locates the inflated ActionBarView,
+     * initializes the ActionBar with the view, and sets mActionBar.
+     */
+    private void initActionBar() {
+        if (!getWindow().hasFeature(Window.FEATURE_ACTION_BAR)) {
+            return;
+        }
+        
+        ActionBarView view = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
+        if (view != null) {
+        	LinearLayout splitView = 
+        		(LinearLayout) findViewById(com.android.internal.R.id.context_action_bar);
+        	if (splitView != null) {
+        		mActionBar = new SplitActionBar(view, splitView);
+        	}
+        } else {
+            Log.e(TAG, "Could not create action bar; view not found in window decor.");
+        }
+    }
+    
+    /**
      * Set the activity content from a layout resource.  The resource will be
      * inflated, adding all top-level views to the activity.
      * 
@@ -1812,6 +1849,7 @@
      */
     public void setContentView(int layoutResID) {
         getWindow().setContentView(layoutResID);
+        initActionBar();
     }
 
     /**
@@ -1823,6 +1861,7 @@
      */
     public void setContentView(View view) {
         getWindow().setContentView(view);
+        initActionBar();
     }
 
     /**
@@ -1835,6 +1874,7 @@
      */
     public void setContentView(View view, ViewGroup.LayoutParams params) {
         getWindow().setContentView(view, params);
+        initActionBar();
     }
 
     /**
@@ -1846,6 +1886,7 @@
      */
     public void addContentView(View view, ViewGroup.LayoutParams params) {
         getWindow().addContentView(view, params);
+        initActionBar();
     }
 
     /**
diff --git a/core/java/android/view/ActionBarView.java b/core/java/android/view/ActionBarView.java
new file mode 100644
index 0000000..941ef21
--- /dev/null
+++ b/core/java/android/view/ActionBarView.java
@@ -0,0 +1,625 @@
+/*
+ * 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 android.view;
+
+import java.util.ArrayList;
+
+import android.app.ActionBar;
+import android.app.Activity;
+import android.app.ActionBar.Callback;
+import android.content.Context;
+import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
+import android.content.res.TypedArray;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+import android.graphics.drawable.Drawable;
+import android.util.AttributeSet;
+import android.util.DisplayMetrics;
+import android.util.SparseArray;
+import android.widget.ImageView;
+import android.widget.TextView;
+
+import com.android.internal.R;
+import com.android.internal.view.menu.ActionMenu;
+import com.android.internal.view.menu.ActionMenuItem;
+
+/**
+ * @hide
+ */
+public class ActionBarView extends ViewGroup {
+    private static final String TAG = "ActionBarView";
+    
+    // TODO: This must be defined in the default theme
+    private static final int CONTENT_HEIGHT_DIP = 50;
+    private static final int CONTENT_PADDING_DIP = 3;
+    private static final int CONTENT_SPACING_DIP = 6;
+    private static final int CONTENT_ACTION_SPACING_DIP = 12;
+    
+    /**
+     * Display options applied by default
+     */
+    public static final int DISPLAY_DEFAULT = 0;
+
+    /**
+     * Display options that require re-layout as opposed to a simple invalidate
+     */
+    private static final int DISPLAY_RELAYOUT_MASK = ActionBar.DISPLAY_USE_LOGO;
+    
+    private final int mContentHeight;
+
+    private int mNavigationMode;
+    private int mDisplayOptions;
+    private int mSpacing;
+    private int mActionSpacing;
+    private CharSequence mTitle;
+    private CharSequence mSubtitle;
+    private Drawable mIcon;
+    private Drawable mLogo;
+    private Drawable mDivider;
+
+    private ImageView mIconView;
+    private ImageView mLogoView;
+    private TextView mTitleView;
+    private TextView mSubtitleView;
+    private View mNavigationView;
+    
+    private boolean mShowMenu;
+
+    private ActionMenuItem mLogoNavItem;
+    private ActionMenu mNavMenu;
+    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.onActionItemSelected(item)) {
+                item.invoke();
+            }
+        }
+    };
+
+    private OnClickListener mHomeClickListener = null;
+
+    public ActionBarView(Context context, AttributeSet attrs) {
+        super(context, attrs);
+
+        final DisplayMetrics metrics = context.getResources().getDisplayMetrics();
+        mContentHeight = (int) (CONTENT_HEIGHT_DIP * metrics.density + 0.5f);
+
+        TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar);
+
+        final int colorFilter = a.getColor(R.styleable.ActionBar_colorFilter, 0);
+
+        if (colorFilter != 0) {
+            final Drawable d = getBackground();
+            d.setDither(true);
+            d.setColorFilter(new PorterDuffColorFilter(colorFilter, PorterDuff.Mode.OVERLAY));
+        }
+
+        ApplicationInfo info = context.getApplicationInfo();
+        PackageManager pm = context.getPackageManager();
+        mNavigationMode = a.getInt(R.styleable.ActionBar_navigationMode, ActionBar.NAVIGATION_MODE_NORMAL);
+        mTitle = a.getText(R.styleable.ActionBar_title);
+        mSubtitle = a.getText(R.styleable.ActionBar_subtitle);
+        mDisplayOptions = a.getInt(R.styleable.ActionBar_displayOptions, DISPLAY_DEFAULT);
+        
+        mLogo = a.getDrawable(R.styleable.ActionBar_logo);
+        if (mLogo == null) {
+            mLogo = info.loadLogo(pm);
+        }
+        mIcon = a.getDrawable(R.styleable.ActionBar_icon);
+        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) {
+            setBackgroundDrawable(background);
+        }
+        
+        final int customNavId = a.getResourceId(R.styleable.ActionBar_customNavigationLayout, 0);
+        if (customNavId != 0) {
+            LayoutInflater inflater = LayoutInflater.from(context);
+            mNavigationView = (View) inflater.inflate(customNavId, null);
+            mNavigationMode = ActionBar.NAVIGATION_MODE_CUSTOM;
+        }
+
+        a.recycle();
+
+        // TODO: Set this in the theme
+        int padding = (int) (CONTENT_PADDING_DIP * metrics.density + 0.5f);
+        setPadding(padding, padding, padding, padding);
+
+        mSpacing = (int) (CONTENT_SPACING_DIP * metrics.density + 0.5f);
+        mActionSpacing = (int) (CONTENT_ACTION_SPACING_DIP * metrics.density + 0.5f);
+        
+        if (mLogo != null || mIcon != null || mTitle != null) {
+            mLogoNavItem = new ActionMenuItem(context, 0, android.R.id.home, 0, 0, mTitle);
+            mHomeClickListener = new OnClickListener() {
+                public void onClick(View v) {
+                    if (mCallback != null) {
+                        mCallback.onActionItemSelected(mLogoNavItem);
+                    }
+                }
+            };
+        }
+        
+        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 setCustomNavigationView(View view) {
+        mNavigationView = view;
+        if (view != null) {
+            setNavigationMode(ActionBar.NAVIGATION_MODE_CUSTOM);
+        }
+        requestLayout();
+    }
+    
+    public void setDividerDrawable(Drawable d) {
+        mDivider = d;
+    }
+    
+    public CharSequence getTitle() {
+        return mTitle;
+    }
+    
+    public void setTitle(CharSequence title) {
+        mTitle = title;
+        if (mTitleView != null) {
+            mTitleView.setText(title);
+        }
+        if (mLogoNavItem != null) {
+            mLogoNavItem.setTitle(title);
+        }
+    }
+    
+    public CharSequence getSubtitle() {
+        return mSubtitle;
+    }
+    
+    public void setSubtitle(CharSequence subtitle) {
+        mSubtitle = subtitle;
+        if (mSubtitleView != null) {
+            mSubtitleView.setText(subtitle);
+        }
+    }
+    
+    public void setDisplayOptions(int options) {
+        final int flagsChanged = options & mDisplayOptions;
+        mDisplayOptions = options;
+        if ((flagsChanged & DISPLAY_RELAYOUT_MASK) != 0) {
+            requestLayout();
+        } else {
+            invalidate();
+        }
+    }
+
+    public void setNavigationMode(int mode) {
+        if (mode != mNavigationMode) {
+            mNavigationMode = mode;
+            requestLayout();
+        }
+    }
+    
+    public View getCustomNavigationView() {
+        return mNavigationView;
+    }
+    
+    public int getNavigationMode() {
+        return mNavigationMode;
+    }
+    
+    public int getDisplayOptions() {
+        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) {
+            throw new IllegalStateException(
+                    "Attempted to set ActionBar context mode with no callback");
+        }
+        
+        ActionMenu menu = mContextMenus.get(mode);
+        if (menu == null) {
+            // Initialize the new mode
+            menu = new ActionMenu(getContext());
+
+            if (!callback.onCreateContextMode(mode, menu)) {
+                throw new IllegalArgumentException(
+                        "ActionBar callback does not know how to create context mode " + mode);
+            }
+            mContextMenus.put(mode, menu);
+        }
+        
+        if (callback.onPrepareContextMode(mode, menu)) {
+            // TODO Set mode, animate, etc.
+        }
+    }
+    
+    public void exitContextMode() {
+        // 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.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();
+
+        if ((mDisplayOptions & ActionBar.DISPLAY_HIDE_HOME) == 0) {
+            if (mLogo != null && (mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) != 0) {
+                mLogoView = new ImageView(getContext());
+                mLogoView.setAdjustViewBounds(true);
+                mLogoView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                        LayoutParams.MATCH_PARENT, LayoutParams.ITEM_TYPE_ICON));
+                mLogoView.setImageDrawable(mLogo);
+                mLogoView.setClickable(true);
+                mLogoView.setOnClickListener(mHomeClickListener);
+                addView(mLogoView);
+            } else if (mIcon != null) {
+                mIconView = new ImageView(getContext());
+                mIconView.setAdjustViewBounds(true);
+                mIconView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                        LayoutParams.MATCH_PARENT, LayoutParams.ITEM_TYPE_ICON));
+                mIconView.setImageDrawable(mIcon);
+                mIconView.setClickable(true);
+                mIconView.setOnClickListener(mHomeClickListener);
+                addView(mIconView);
+            }
+        }
+
+        switch (mNavigationMode) {
+        case ActionBar.NAVIGATION_MODE_NORMAL:
+            if (mLogoView == null) {
+                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));
+                if (mTitle != null) {
+                    mTitleView.setText(mTitle);
+                }
+                mTitleView.setClickable(true);
+                mTitleView.setOnClickListener(mHomeClickListener);
+                addView(mTitleView);
+            }
+            break;
+            
+        case ActionBar.NAVIGATION_MODE_DROPDOWN_LIST:
+            throw new UnsupportedOperationException(
+                    "Dropdown list navigation isn't supported yet!");
+            
+        case ActionBar.NAVIGATION_MODE_TABS:
+            throw new UnsupportedOperationException(
+                    "Tab navigation isn't supported yet!");
+            
+        case ActionBar.NAVIGATION_MODE_CUSTOM:
+            if (mNavigationView != null) {
+                mNavigationView.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT,
+                        LayoutParams.WRAP_CONTENT, LayoutParams.ITEM_TYPE_CUSTOM_NAV));
+                addView(mNavigationView);
+            }
+            break;
+        }
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
+        if (widthMode != MeasureSpec.EXACTLY) {
+            throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
+                    "with android:layout_width=\"match_parent\" (or fill_parent)");
+        }
+        
+        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
+        if (heightMode != MeasureSpec.AT_MOST) {
+            throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
+                    "with android:layout_height=\"wrap_content\"");
+        }
+
+        int contentWidth = MeasureSpec.getSize(widthMeasureSpec);
+        
+        int availableWidth = contentWidth - getPaddingLeft() - getPaddingRight();
+        int childSpecHeight = MeasureSpec.makeMeasureSpec(mContentHeight - getPaddingTop() -
+                getPaddingBottom(), MeasureSpec.AT_MOST);
+
+        if (mLogoView != null) {
+            availableWidth = measureChildView(mLogoView, availableWidth, childSpecHeight, mSpacing);
+        }
+        if (mIconView != null) {
+            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,
+                    childSpecHeight, mActionSpacing);
+        }
+        
+        switch (mNavigationMode) {
+        case ActionBar.NAVIGATION_MODE_NORMAL:
+            if (mTitleView != null) {
+                availableWidth = measureChildView(mTitleView, availableWidth,
+                        childSpecHeight, mSpacing);
+            }
+            break;
+        case ActionBar.NAVIGATION_MODE_CUSTOM:
+            if (mNavigationView != null) {
+                availableWidth = measureChildView(mNavigationView, availableWidth,
+                        childSpecHeight, mSpacing);
+            }
+            break;
+        }
+
+        setMeasuredDimension(contentWidth, mContentHeight);
+    }
+
+    private int measureChildView(View child, int availableWidth, int childSpecHeight, int spacing) {
+        measureChild(child,
+                MeasureSpec.makeMeasureSpec(availableWidth, MeasureSpec.AT_MOST),
+                childSpecHeight);
+
+        availableWidth -= child.getMeasuredWidth();
+        availableWidth -= spacing;
+
+        return availableWidth;
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        int x = getPaddingLeft();
+        final int y = getPaddingTop();
+        final int contentHeight = b - t - getPaddingTop() - getPaddingBottom();
+
+        if (mLogoView != null) {
+            x += positionChild(mLogoView, x, y, contentHeight) + mSpacing;
+        }
+        if (mIconView != null) {
+            x += positionChild(mIconView, x, y, contentHeight) + mSpacing;
+        }
+        
+        switch (mNavigationMode) {
+        case ActionBar.NAVIGATION_MODE_NORMAL:
+            if (mTitleView != null) {
+                x += positionChild(mTitleView, x, y, contentHeight) + mSpacing;
+            }
+            break;
+            
+        case ActionBar.NAVIGATION_MODE_CUSTOM:
+            if (mNavigationView != null) {
+                x += positionChild(mNavigationView, x, y, contentHeight) + mSpacing;
+            }
+            break;
+        }
+
+        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);
+        }
+    }
+
+    private int positionChild(View child, int x, int y, int contentHeight) {
+        int childWidth = child.getMeasuredWidth();
+        int childHeight = child.getMeasuredHeight();
+        int childTop = y + (contentHeight - childHeight) / 2;
+
+        child.layout(x, childTop, x + childWidth, childTop + childHeight);
+
+        return childWidth;
+    }
+    
+    private int positionChildInverse(View child, int x, int y, int contentHeight) {
+        int childWidth = child.getMeasuredWidth();
+        int childHeight = child.getMeasuredHeight();
+        int childTop = y + (contentHeight - childHeight) / 2;
+
+        child.layout(x - childWidth, childTop, x, childTop + childHeight);
+
+        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 46c805c..a37d83d 100644
--- a/core/java/android/view/MenuInflater.java
+++ b/core/java/android/view/MenuInflater.java
@@ -16,9 +16,8 @@
 
 package android.view;
 
-import com.android.internal.view.menu.MenuItemImpl;
-
 import java.io.IOException;
+import java.lang.reflect.Method;
 
 import org.xmlpull.v1.XmlPullParser;
 import org.xmlpull.v1.XmlPullParserException;
@@ -30,6 +29,8 @@
 import android.util.AttributeSet;
 import android.util.Xml;
 
+import com.android.internal.view.menu.MenuItemImpl;
+
 /**
  * This class is used to instantiate menu XML files into Menu objects.
  * <p>
@@ -166,6 +167,41 @@
         }
     }
     
+    private static class InflatedOnMenuItemClickListener
+            implements MenuItem.OnMenuItemClickListener {
+        private static final Class[] PARAM_TYPES = new Class[] { MenuItem.class };
+        
+        private Context mContext;
+        private Method mMethod;
+        
+        public InflatedOnMenuItemClickListener(Context context, String methodName) {
+            mContext = context;
+            Class c = context.getClass();
+            try {
+                mMethod = c.getMethod(methodName, PARAM_TYPES);
+            } catch (Exception e) {
+                InflateException ex = new InflateException(
+                        "Couldn't resolve menu item onClick handler " + methodName +
+                        " in class " + c.getName());
+                ex.initCause(e);
+                throw ex;
+            }
+        }
+        
+        public boolean onMenuItemClick(MenuItem item) {
+            try {
+                if (mMethod.getReturnType() == Boolean.TYPE) {
+                    return (Boolean) mMethod.invoke(mContext, item);
+                } else {
+                    mMethod.invoke(mContext, item);
+                    return true;
+                }
+            } catch (Exception e) {
+                throw new RuntimeException(e);
+            }
+        }
+    }
+    
     /**
      * State for the current menu.
      * <p>
@@ -205,6 +241,8 @@
         private boolean itemVisible;
         private boolean itemEnabled;
         
+        private String itemListenerMethodName;
+        
         private static final int defaultGroupId = NO_ID;
         private static final int defaultItemId = NO_ID;
         private static final int defaultItemCategory = 0;
@@ -276,6 +314,7 @@
             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);
+            itemListenerMethodName = a.getString(com.android.internal.R.styleable.MenuItem_onClick);
             
             a.recycle();
             
@@ -299,8 +338,13 @@
                 .setIcon(itemIconResId)
                 .setAlphabeticShortcut(itemAlphabeticShortcut)
                 .setNumericShortcut(itemNumericShortcut);
+            
+            if (itemListenerMethodName != null) {
+                item.setOnMenuItemClickListener(
+                        new InflatedOnMenuItemClickListener(mContext, itemListenerMethodName));
+            }
 
-            if (itemCheckable >= 2) {
+            if (itemCheckable >= 2 && item instanceof MenuItemImpl) {
                 ((MenuItemImpl) item).setExclusiveCheckable(true);
             }
         }
diff --git a/core/java/android/view/Window.java b/core/java/android/view/Window.java
index 7dd5085..e1ff4e8 100644
--- a/core/java/android/view/Window.java
+++ b/core/java/android/view/Window.java
@@ -61,6 +61,13 @@
         @hide
     */
     public static final int FEATURE_OPENGL = 8;
+    /**
+     * Flag for enabling the Action Bar.
+     * This is enabled by default for some devices. The Action Bar
+     * replaces the title bar and provides an alternate location
+     * for an on-screen menu button on some devices.
+     */
+    public static final int FEATURE_ACTION_BAR = 9;
     /** Flag for setting the progress bar's visibility to VISIBLE */
     public static final int PROGRESS_VISIBILITY_ON = -1;
     /** Flag for setting the progress bar's visibility to GONE */
@@ -981,6 +988,16 @@
     {
         return mFeatures;
     }
+    
+    /**
+     * Query for the availability of a certain feature.
+     * 
+     * @param feature The feature ID to check
+     * @return true if the feature is enabled, false otherwise.
+     */
+    public boolean hasFeature(int feature) {
+        return (getFeatures() & (1 << feature)) != 0;
+    }
 
     /**
      * Return the feature bits that are being implemented by this Window.
diff --git a/core/java/com/android/internal/app/SplitActionBar.java b/core/java/com/android/internal/app/SplitActionBar.java
new file mode 100644
index 0000000..4e19e04
--- /dev/null
+++ b/core/java/com/android/internal/app/SplitActionBar.java
@@ -0,0 +1,97 @@
+/*
+ * 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.app;
+
+import android.app.ActionBar;
+import android.graphics.drawable.Drawable;
+import android.view.ActionBarView;
+import android.view.View;
+import android.widget.LinearLayout;
+
+/**
+ * SplitActionBar is the ActionBar implementation used
+ * by small-screen devices. It expects to split contextual
+ * modes across both the ActionBarView at the top of the screen
+ * and a horizontal LinearLayout at the bottom which is normally
+ * hidden.
+ */
+public class SplitActionBar extends ActionBar {
+    private ActionBarView mActionView;
+    private LinearLayout mContextView;
+    
+    public SplitActionBar(ActionBarView view, LinearLayout contextView) {
+        mActionView = view;
+        mContextView = contextView;
+    }
+    
+    public void setCallback(Callback callback) {
+        mActionView.setCallback(callback);
+    }
+
+    public void setCustomNavigationView(View view) {
+        mActionView.setCustomNavigationView(view);
+    }
+
+    public void setTitle(CharSequence title) {
+        mActionView.setTitle(title);
+    }
+
+    public void setSubtitle(CharSequence subtitle) {
+        mActionView.setSubtitle(subtitle);
+    }
+
+    public void setNavigationMode(int mode) {
+        mActionView.setNavigationMode(mode);
+    }
+
+    public void setDisplayOptions(int options) {
+        mActionView.setDisplayOptions(options);
+    }
+
+    public void setBackgroundDrawable(Drawable d) {
+        mActionView.setBackgroundDrawable(d);
+    }
+
+    public void setDividerDrawable(Drawable d) {
+        mActionView.setDividerDrawable(d);
+    }
+
+    public View getCustomNavigationView() {
+        return mActionView.getCustomNavigationView();
+    }
+
+    public CharSequence getTitle() {
+        return mActionView.getTitle();
+    }
+
+    public CharSequence getSubtitle() {
+        return mActionView.getSubtitle();
+    }
+
+    public int getNavigationMode() {
+        return mActionView.getNavigationMode();
+    }
+
+    public int getDisplayOptions() {
+        return mActionView.getDisplayOptions();
+    }
+
+    public void updateActionMenu() {
+        mActionView.updateActionMenu();
+    }
+
+}
diff --git a/core/java/com/android/internal/view/menu/ActionMenu.java b/core/java/com/android/internal/view/menu/ActionMenu.java
new file mode 100644
index 0000000..3d44ebc
--- /dev/null
+++ b/core/java/com/android/internal/view/menu/ActionMenu.java
@@ -0,0 +1,263 @@
+/*
+ * 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 java.util.ArrayList;
+import java.util.List;
+
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.PackageManager;
+import android.content.pm.ResolveInfo;
+import android.view.KeyEvent;
+import android.view.Menu;
+import android.view.MenuItem;
+import android.view.SubMenu;
+
+/**
+ * @hide
+ */
+public class ActionMenu implements Menu {
+    private Context mContext;
+    
+    private boolean mIsQwerty;
+    
+    private ArrayList<ActionMenuItem> mItems;
+    
+    public ActionMenu(Context context) {
+        mContext = context;
+        mItems = new ArrayList<ActionMenuItem>();
+    }
+    
+    public Context getContext() {
+        return mContext;
+    }
+
+    public MenuItem add(CharSequence title) {
+        return add(0, 0, 0, title);
+    }
+
+    public MenuItem add(int titleRes) {
+        return add(0, 0, 0, titleRes);
+    }
+
+    public MenuItem add(int groupId, int itemId, int order, int titleRes) {
+        return add(groupId, itemId, order, mContext.getResources().getString(titleRes));
+    }
+    
+    public MenuItem add(int groupId, int itemId, int order, CharSequence title) {
+        ActionMenuItem item = new ActionMenuItem(getContext(),
+                groupId, itemId, 0, order, title);
+        mItems.add(order, item);
+        return item;
+    }
+
+    public int addIntentOptions(int groupId, int itemId, int order,
+            ComponentName caller, Intent[] specifics, Intent intent, int flags,
+            MenuItem[] outSpecificItems) {
+        PackageManager pm = mContext.getPackageManager();
+        final List<ResolveInfo> lri =
+                pm.queryIntentActivityOptions(caller, specifics, intent, 0);
+        final int N = lri != null ? lri.size() : 0;
+
+        if ((flags & FLAG_APPEND_TO_GROUP) == 0) {
+            removeGroup(groupId);
+        }
+
+        for (int i=0; i<N; i++) {
+            final ResolveInfo ri = lri.get(i);
+            Intent rintent = new Intent(
+                ri.specificIndex < 0 ? intent : specifics[ri.specificIndex]);
+            rintent.setComponent(new ComponentName(
+                    ri.activityInfo.applicationInfo.packageName,
+                    ri.activityInfo.name));
+            final MenuItem item = add(groupId, itemId, order, ri.loadLabel(pm))
+                    .setIcon(ri.loadIcon(pm))
+                    .setIntent(rintent);
+            if (outSpecificItems != null && ri.specificIndex >= 0) {
+                outSpecificItems[ri.specificIndex] = item;
+            }
+        }
+
+        return N;
+    }
+
+    public SubMenu addSubMenu(CharSequence title) {
+        // TODO Implement submenus
+        return null;
+    }
+
+    public SubMenu addSubMenu(int titleRes) {
+        // TODO Implement submenus
+        return null;
+    }
+
+    public SubMenu addSubMenu(int groupId, int itemId, int order,
+            CharSequence title) {
+        // TODO Implement submenus
+        return null;
+    }
+
+    public SubMenu addSubMenu(int groupId, int itemId, int order, int titleRes) {
+        // TODO Implement submenus
+        return null;
+    }
+
+    public void clear() {
+        mItems.clear();
+    }
+
+    public void close() {
+    }
+    
+    private int findItemIndex(int id) {
+        final ArrayList<ActionMenuItem> items = mItems;
+        final int itemCount = items.size();
+        for (int i = 0; i < itemCount; i++) {
+            if (items.get(i).getItemId() == id) {
+                return i;
+            }
+        }
+        
+        return -1;
+    }
+
+    public MenuItem findItem(int id) {
+        return mItems.get(findItemIndex(id));
+    }
+
+    public MenuItem getItem(int index) {
+        return mItems.get(index);
+    }
+
+    public boolean hasVisibleItems() {
+        final ArrayList<ActionMenuItem> items = mItems;
+        final int itemCount = items.size();
+        
+        for (int i = 0; i < itemCount; i++) {
+            if (items.get(i).isVisible()) {
+                return true;
+            }
+        }
+        
+        return false;
+    }
+    
+    private ActionMenuItem findItemWithShortcut(int keyCode, KeyEvent event) {
+        // TODO Make this smarter.
+        final boolean qwerty = mIsQwerty;
+        final ArrayList<ActionMenuItem> items = mItems;
+        final int itemCount = items.size();
+        
+        for (int i = 0; i < itemCount; i++) {
+            ActionMenuItem item = items.get(i);
+            final char shortcut = qwerty ? item.getAlphabeticShortcut() :
+                    item.getNumericShortcut();
+            if (keyCode == shortcut) {
+                return item;
+            }
+        }
+        return null;
+    }
+
+    public boolean isShortcutKey(int keyCode, KeyEvent event) {
+        return findItemWithShortcut(keyCode, event) != null;
+    }
+
+    public boolean performIdentifierAction(int id, int flags) {
+        final int index = findItemIndex(id);
+        if (index < 0) {
+            return false;
+        }
+
+        return mItems.get(index).invoke();
+    }
+
+    public boolean performShortcut(int keyCode, KeyEvent event, int flags) {
+        ActionMenuItem item = findItemWithShortcut(keyCode, event);
+        if (item == null) {
+            return false;
+        }
+        
+        return item.invoke();
+    }
+
+    public void removeGroup(int groupId) {
+        final ArrayList<ActionMenuItem> items = mItems;
+        int itemCount = items.size();
+        int i = 0;
+        while (i < itemCount) {
+            if (items.get(i).getGroupId() == groupId) {
+                items.remove(i);
+                itemCount--;
+            } else {
+                i++;
+            }
+        }
+    }
+
+    public void removeItem(int id) {
+        mItems.remove(findItemIndex(id));
+    }
+
+    public void setGroupCheckable(int group, boolean checkable,
+            boolean exclusive) {
+        final ArrayList<ActionMenuItem> items = mItems;
+        final int itemCount = items.size();
+        
+        for (int i = 0; i < itemCount; i++) {
+            ActionMenuItem item = items.get(i);
+            if (item.getGroupId() == group) {
+                item.setCheckable(checkable);
+                item.setExclusiveCheckable(exclusive);
+            }
+        }
+    }
+
+    public void setGroupEnabled(int group, boolean enabled) {
+        final ArrayList<ActionMenuItem> items = mItems;
+        final int itemCount = items.size();
+        
+        for (int i = 0; i < itemCount; i++) {
+            ActionMenuItem item = items.get(i);
+            if (item.getGroupId() == group) {
+                item.setEnabled(enabled);
+            }
+        }
+    }
+
+    public void setGroupVisible(int group, boolean visible) {
+        final ArrayList<ActionMenuItem> items = mItems;
+        final int itemCount = items.size();
+        
+        for (int i = 0; i < itemCount; i++) {
+            ActionMenuItem item = items.get(i);
+            if (item.getGroupId() == group) {
+                item.setVisible(visible);
+            }
+        }
+    }
+
+    public void setQwertyMode(boolean isQwerty) {
+        mIsQwerty = isQwerty;
+    }
+
+    public int size() {
+        return mItems.size();
+    }
+}
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItem.java b/core/java/com/android/internal/view/menu/ActionMenuItem.java
new file mode 100644
index 0000000..47d5fb9
--- /dev/null
+++ b/core/java/com/android/internal/view/menu/ActionMenuItem.java
@@ -0,0 +1,221 @@
+/*
+ * 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.content.Intent;
+import android.graphics.drawable.Drawable;
+import android.view.MenuItem;
+import android.view.SubMenu;
+import android.view.ContextMenu.ContextMenuInfo;
+
+/**
+ * @hide
+ */
+public class ActionMenuItem implements MenuItem {
+    private final int mId;
+    private final int mGroup;
+    private final int mCategoryOrder;
+    private final int mOrdering;
+    
+    private CharSequence mTitle;
+    private CharSequence mTitleCondensed;
+    private Intent mIntent;
+    private char mShortcutNumericChar;
+    private char mShortcutAlphabeticChar;
+    
+    private Drawable mIconDrawable;
+    private int mIconResId = NO_ICON;
+    
+    private Context mContext;
+    
+    private MenuItem.OnMenuItemClickListener mClickListener;
+    
+    private static final int NO_ICON = 0;
+    
+    private int mFlags = ENABLED;
+    private static final int CHECKABLE      = 0x00000001;
+    private static final int CHECKED        = 0x00000002;
+    private static final int EXCLUSIVE      = 0x00000004;
+    private static final int HIDDEN         = 0x00000008;
+    private static final int ENABLED        = 0x00000010;
+    
+    public ActionMenuItem(Context context, int group, int id, int categoryOrder, int ordering,
+            CharSequence title) {
+        mContext = context;
+        mId = id;
+        mGroup = group;
+        mCategoryOrder = categoryOrder;
+        mOrdering = ordering;
+        mTitle = title;
+    }
+    
+    public char getAlphabeticShortcut() {
+        return mShortcutAlphabeticChar;
+    }
+
+    public int getGroupId() {
+        return mGroup;
+    }
+
+    public Drawable getIcon() {
+        return mIconDrawable;
+    }
+
+    public Intent getIntent() {
+        return mIntent;
+    }
+
+    public int getItemId() {
+        return mId;
+    }
+
+    public ContextMenuInfo getMenuInfo() {
+        return null;
+    }
+
+    public char getNumericShortcut() {
+        return mShortcutNumericChar;
+    }
+
+    public int getOrder() {
+        return mOrdering;
+    }
+
+    public SubMenu getSubMenu() {
+        return null;
+    }
+
+    public CharSequence getTitle() {
+        return mTitle;
+    }
+
+    public CharSequence getTitleCondensed() {
+        return mTitleCondensed;
+    }
+
+    public boolean hasSubMenu() {
+        return false;
+    }
+
+    public boolean isCheckable() {
+        return (mFlags & CHECKABLE) != 0; 
+    }
+
+    public boolean isChecked() {
+        return (mFlags & CHECKED) != 0;
+    }
+
+    public boolean isEnabled() {
+        return (mFlags & ENABLED) != 0;
+    }
+
+    public boolean isVisible() {
+        return (mFlags & HIDDEN) == 0;
+    }
+
+    public MenuItem setAlphabeticShortcut(char alphaChar) {
+        mShortcutAlphabeticChar = alphaChar;
+        return this;
+    }
+
+    public MenuItem setCheckable(boolean checkable) {
+        mFlags = (mFlags & ~CHECKABLE) | (checkable ? CHECKABLE : 0);
+        return this;
+    }
+    
+    public ActionMenuItem setExclusiveCheckable(boolean exclusive) {
+        mFlags = (mFlags & ~EXCLUSIVE) | (exclusive ? EXCLUSIVE : 0);
+        return this;
+    }
+
+    public MenuItem setChecked(boolean checked) {
+        mFlags = (mFlags & ~CHECKED) | (checked ? CHECKED : 0);
+        return this;
+    }
+
+    public MenuItem setEnabled(boolean enabled) {
+        mFlags = (mFlags & ~ENABLED) | (enabled ? ENABLED : 0);
+        return this;
+    }
+
+    public MenuItem setIcon(Drawable icon) {
+        mIconDrawable = icon;
+        mIconResId = NO_ICON;
+        return this;
+    }
+
+    public MenuItem setIcon(int iconRes) {
+        mIconResId = iconRes;
+        mIconDrawable = mContext.getResources().getDrawable(iconRes);
+        return this;
+    }
+
+    public MenuItem setIntent(Intent intent) {
+        mIntent = intent;
+        return this;
+    }
+
+    public MenuItem setNumericShortcut(char numericChar) {
+        mShortcutNumericChar = numericChar;
+        return this;
+    }
+
+    public MenuItem setOnMenuItemClickListener(OnMenuItemClickListener menuItemClickListener) {
+        mClickListener = menuItemClickListener;
+        return this;
+    }
+
+    public MenuItem setShortcut(char numericChar, char alphaChar) {
+        mShortcutNumericChar = numericChar;
+        mShortcutAlphabeticChar = alphaChar;
+        return this;
+    }
+
+    public MenuItem setTitle(CharSequence title) {
+        mTitle = title;
+        return this;
+    }
+
+    public MenuItem setTitle(int title) {
+        mTitle = mContext.getResources().getString(title);
+        return this;
+    }
+
+    public MenuItem setTitleCondensed(CharSequence title) {
+        mTitleCondensed = title;
+        return this;
+    }
+
+    public MenuItem setVisible(boolean visible) {
+        mFlags = (mFlags & HIDDEN) | (visible ? 0 : HIDDEN);
+        return this;
+    }
+
+    public boolean invoke() {
+        if (mClickListener != null && mClickListener.onMenuItemClick(this)) {
+            return true;
+        }
+        
+        if (mIntent != null) {
+            mContext.startActivity(mIntent);
+            return true;
+        }
+        
+        return false;
+    }
+}
diff --git a/core/res/res/drawable/action_bar_background.xml b/core/res/res/drawable/action_bar_background.xml
new file mode 100644
index 0000000..3929d7f
--- /dev/null
+++ b/core/res/res/drawable/action_bar_background.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <gradient
+        android:startColor="#ffd1d2d4"
+        android:endColor="#ff85878a"
+        android:angle="270" />
+</shape>
diff --git a/core/res/res/drawable/action_bar_divider.xml b/core/res/res/drawable/action_bar_divider.xml
new file mode 100644
index 0000000..414309f
--- /dev/null
+++ b/core/res/res/drawable/action_bar_divider.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<shape xmlns:android="http://schemas.android.com/apk/res/android">
+    <gradient
+        android:startColor="#ffe1e2e4"
+        android:endColor="#ff95979a"
+        android:angle="270" />
+</shape>
diff --git a/core/res/res/layout/action_bar_title_item.xml b/core/res/res/layout/action_bar_title_item.xml
new file mode 100644
index 0000000..d7f7c13
--- /dev/null
+++ b/core/res/res/layout/action_bar_title_item.xml
@@ -0,0 +1,22 @@
+<?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.
+-->
+
+<TextView
+    xmlns:android="http://schemas.android.com/apk/res/android"
+
+    android:singleLine="true"
+    android:ellipsize="end"
+    android:textAppearance="?android:attr/textAppearanceMediumInverse" />
diff --git a/core/res/res/layout/screen_action_bar.xml b/core/res/res/layout/screen_action_bar.xml
new file mode 100644
index 0000000..01a4b42
--- /dev/null
+++ b/core/res/res/layout/screen_action_bar.xml
@@ -0,0 +1,40 @@
+<?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.
+-->
+
+<!--
+This is an optimized layout for a screen with the Action Bar enabled.
+-->
+
+<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
+    android:orientation="vertical"
+    android:fitsSystemWindows="true">
+    <ActionBarView android:id="@+id/action_bar"
+               android:layout_width="match_parent"
+               android:layout_height="wrap_content"
+               style="?android:attr/windowActionBarStyle" />
+    <FrameLayout android:id="@android:id/content"
+        android:layout_width="match_parent" 
+        android:layout_height="0dip"
+        android:layout_weight="1"
+        android:foregroundGravity="fill_horizontal|top"
+        android:foreground="?android:attr/windowContentOverlay" />
+    <LinearLayout android:id="@+id/context_action_bar"
+                  android:layout_width="match_parent"
+                  android:layout_height="wrap_content"
+                  style="?android:attr/windowActionBarStyle"
+                  android:visibility="gone" />
+</LinearLayout>
+
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index 1449b02..e7b83c7 100755
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -244,6 +244,13 @@
              {@link android.R.styleable#WindowAnimation}. -->
         <attr name="windowAnimationStyle" format="reference" />
 
+        <!-- Flag indicating whether this window should have an Action Bar
+             in place of the usual title bar. -->
+        <attr name="windowActionBar" format="boolean" />
+
+        <!-- Reference to a style for the Action Bar -->
+        <attr name="windowActionBarStyle" format="reference" />
+
         <!-- Defines the default soft input state that this window would
              like when it is displayed. -->
         <attr name="windowSoftInputMode">
@@ -948,6 +955,8 @@
         <attr name="textColor" />
         <attr name="backgroundDimEnabled" />
         <attr name="backgroundDimAmount" />
+        <attr name="windowActionBar" />
+        <attr name="windowActionBarStyle" />
     </declare-styleable>
 
     <!-- The set of attributes that describe a AlertDialog's theme. -->
@@ -3243,6 +3252,10 @@
         <!-- Whether the item is enabled. -->
         <attr name="enabled" />
 
+        <!-- Name of a method on the Context used to inflate the menu that will be
+             called when the item is clicked. -->
+        <attr name="onClick" />
+
     </declare-styleable>
 
     <!-- **************************************************************** -->
@@ -3762,4 +3775,42 @@
         <attr name="withClass" format="string" />
     </declare-styleable>
 
+    <!-- Attributes used to style the Action Bar. -->
+    <declare-styleable name="ActionBar">
+        <!-- The type of navigation to use. -->
+        <attr name="navigationMode">
+            <!-- Normal static title text -->
+            <enum name="normal" value="0" />
+            <!-- The action bar will use a drop-down selection in place of title text. -->
+            <enum name="dropdownList" value="1" />
+            <!-- The action bar will use a series of horizontal tabs in place of title text. -->
+            <enum name="tabBar" value="2" />
+        </attr>
+        <!-- Options affecting how the action bar is displayed. -->
+        <attr name="displayOptions">
+            <flag name="useLogo" value="1" />
+            <flag name="hideHome" value="2" />
+        </attr>
+        <!-- Specifies the color used to style the action bar. -->
+        <attr name="colorFilter" format="color" />
+        <!-- Specifies title text used for navigationMode="normal" -->
+        <attr name="title" />
+        <!-- Specifies subtitle text used for navigationMode="normal" -->
+        <attr name="subtitle" format="string" />
+        <!-- Specifies a style to use for title text. -->
+        <attr name="titleTextStyle" format="reference" />
+        <!-- Specifies a style to use for subtitle text. -->
+        <attr name="subtitleTextStyle" format="reference" />
+        <!-- Specifies the drawable used for the application icon. -->
+        <attr name="icon" />
+        <!-- Specifies the drawable used for the application logo. -->
+        <attr name="logo" />
+        <!-- Specifies the drawable used for item dividers. -->
+        <attr name="divider" />
+        <!-- Specifies a background drawable for the action bar. -->
+        <attr name="background" />
+        <!-- Specifies a layout for custom navigation. Overrides navigationMode. -->
+        <attr name="customNavigationLayout" format="reference" />
+    </declare-styleable>
+
 </resources>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index 8b6af71..e607fad5 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -68,4 +68,5 @@
   <item type="id" name="accountPreferences" />
   <item type="id" name="smallIcon" />
   <item type="id" name="custom" />
+  <item type="id" name="home" />
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index fe27174..9055970 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -1275,5 +1275,15 @@
   <public type="attr" name="withExpression" />
   <public type="attr" name="withClass" />
   <public type="attr" name="allContactsName" />
+  <public type="attr" name="windowActionBar" />
+  <public type="attr" name="windowActionBarStyle" />
+  <public type="attr" name="navigationMode" />
+  <public type="attr" name="displayOptions" />
+  <public type="attr" name="subtitle" />
+  <public type="attr" name="customNavigationLayout" />
+
+  <public type="id" name="home" />
+
+  <public type="style" name="Theme.WithActionBar" />
 
 </resources>
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index f9b0667..73c3444 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -840,4 +840,10 @@
         <item name="android:paddingBottom">1dip</item>
         <item name="android:background">@android:drawable/bottom_bar</item>
     </style>
+
+    <style name="ActionBar">
+        <item name="android:background">@android:drawable/action_bar_background</item>
+        <item name="android:displayOptions">useLogo</item>
+        <item name="android:divider">@android:drawable/action_bar_divider</item>
+    </style>
 </resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index d585d9e..32c5f47 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -115,6 +115,8 @@
         <item name="windowTitleBackgroundStyle">@android:style/WindowTitleBackground</item>
         <item name="android:windowAnimationStyle">@android:style/Animation.Activity</item>
         <item name="android:windowSoftInputMode">stateUnspecified|adjustUnspecified</item>
+        <item name="windowActionBar">false</item>
+        <item name="windowActionBarStyle">@android:style/ActionBar</item>
 
         <!-- Dialog attributes -->
         <item name="alertDialogStyle">@android:style/AlertDialog</item>
@@ -521,5 +523,9 @@
         <item name="android:windowAnimationStyle">@android:style/Animation.RecentApplications</item>
         <item name="android:textColor">@android:color/secondary_text_nofocus</item>
     </style>
+
+    <style name="Theme.WithActionBar">
+        <item name="android:windowActionBar">true</item>
+    </style>
     
 </resources>