android.widget.Toolbar

Add the new Toolbar widget for use in app layouts.

ActionBar can now be used as a point of control for either a
traditional window decor action bar or for a Toolbar that appears
inline in an Activity's layout.

ToolbarActionBar is currently WIP.

Change-Id: I0da093e5645840f4fd032aa34efa0ae5f1825ff2
diff --git a/api/current.txt b/api/current.txt
index 73cf152..5d875a0 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1075,6 +1075,7 @@
     field public static final int strokeOpacity = 16843812; // 0x1010424
     field public static final int strokeWidth = 16843813; // 0x1010425
     field public static final int subtitle = 16843473; // 0x10102d1
+    field public static final int subtitleTextAppearance = 16843834; // 0x101043a
     field public static final int subtitleTextStyle = 16843513; // 0x10102f9
     field public static final int subtypeExtraValue = 16843674; // 0x101039a
     field public static final int subtypeId = 16843713; // 0x10103c1
@@ -1190,6 +1191,7 @@
     field public static final int tintMode = 16843798; // 0x1010416
     field public static final int title = 16843233; // 0x10101e1
     field public static final int titleCondensed = 16843234; // 0x10101e2
+    field public static final int titleTextAppearance = 16843833; // 0x1010439
     field public static final int titleTextStyle = 16843512; // 0x10102f8
     field public static final int toAlpha = 16843211; // 0x10101cb
     field public static final int toDegrees = 16843188; // 0x10101b4
@@ -3088,6 +3090,7 @@
     ctor public ActionBar.LayoutParams(int);
     ctor public ActionBar.LayoutParams(android.app.ActionBar.LayoutParams);
     ctor public ActionBar.LayoutParams(android.view.ViewGroup.LayoutParams);
+    ctor public ActionBar.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
     field public int gravity;
   }
 
@@ -3263,6 +3266,7 @@
     method public void reportFullyDrawn();
     method public final boolean requestWindowFeature(int);
     method public final void runOnUiThread(java.lang.Runnable);
+    method public void setActionBar(android.widget.Toolbar);
     method public void setActivityLabelAndIcon(java.lang.CharSequence, android.graphics.Bitmap);
     method public void setContentTransitionManager(android.transition.TransitionManager);
     method public void setContentView(int);
@@ -32514,6 +32518,7 @@
     method public android.view.Menu getMenu();
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public void onDetachedFromWindow();
+    method public void setOnMenuItemClickListener(android.widget.ActionMenuView.OnMenuItemClickListener);
   }
 
   public static class ActionMenuView.LayoutParams extends android.widget.LinearLayout.LayoutParams {
@@ -32523,6 +32528,10 @@
     ctor public ActionMenuView.LayoutParams(int, int);
   }
 
+  public static abstract interface ActionMenuView.OnMenuItemClickListener {
+    method public abstract boolean onMenuItemClick(android.view.MenuItem);
+  }
+
   public abstract interface Adapter {
     method public abstract int getCount();
     method public abstract java.lang.Object getItem(int);
@@ -34676,6 +34685,50 @@
     method public void setTextOn(java.lang.CharSequence);
   }
 
+  public class Toolbar extends android.view.ViewGroup {
+    ctor public Toolbar(android.content.Context);
+    ctor public Toolbar(android.content.Context, android.util.AttributeSet);
+    ctor public Toolbar(android.content.Context, android.util.AttributeSet, int);
+    ctor public Toolbar(android.content.Context, android.util.AttributeSet, int, int);
+    method public android.graphics.drawable.Drawable getLogo();
+    method public java.lang.CharSequence getLogoDescription();
+    method public android.view.Menu getMenu();
+    method public android.graphics.drawable.Drawable getNavigationIcon();
+    method public java.lang.CharSequence getSubtitle();
+    method public java.lang.CharSequence getTitle();
+    method public void inflateMenu(int);
+    method protected void onLayout(boolean, int, int, int, int);
+    method public void setLogo(int);
+    method public void setLogo(android.graphics.drawable.Drawable);
+    method public void setLogoDescription(int);
+    method public void setLogoDescription(java.lang.CharSequence);
+    method public void setNavigationDescription(int);
+    method public void setNavigationDescription(java.lang.CharSequence);
+    method public void setNavigationIcon(int);
+    method public void setNavigationIcon(android.graphics.drawable.Drawable);
+    method public void setNavigationOnClickListener(android.view.View.OnClickListener);
+    method public void setOnMenuItemClickListener(android.widget.Toolbar.OnMenuItemClickListener);
+    method public void setSubtitle(int);
+    method public void setSubtitle(java.lang.CharSequence);
+    method public void setTitle(int);
+    method public void setTitle(java.lang.CharSequence);
+  }
+
+  public static class Toolbar.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+    ctor public Toolbar.LayoutParams(android.content.Context, android.util.AttributeSet);
+    ctor public Toolbar.LayoutParams(int, int);
+    ctor public Toolbar.LayoutParams(int, int, int);
+    ctor public Toolbar.LayoutParams(int);
+    ctor public Toolbar.LayoutParams(android.widget.Toolbar.LayoutParams);
+    ctor public Toolbar.LayoutParams(android.view.ViewGroup.MarginLayoutParams);
+    ctor public Toolbar.LayoutParams(android.view.ViewGroup.LayoutParams);
+    field public int gravity;
+  }
+
+  public static abstract interface Toolbar.OnMenuItemClickListener {
+    method public abstract boolean onMenuItemClick(android.view.MenuItem);
+  }
+
   public deprecated class TwoLineListItem extends android.widget.RelativeLayout {
     ctor public TwoLineListItem(android.content.Context);
     ctor public TwoLineListItem(android.content.Context, android.util.AttributeSet);
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 29c1c569..13ae352 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -20,9 +20,11 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.Context;
+import android.content.res.Configuration;
 import android.content.res.TypedArray;
 import android.graphics.drawable.Drawable;
 import android.util.AttributeSet;
+import android.view.ActionMode;
 import android.view.Gravity;
 import android.view.View;
 import android.view.ViewDebug;
@@ -30,31 +32,57 @@
 import android.view.ViewGroup.MarginLayoutParams;
 import android.view.Window;
 import android.widget.SpinnerAdapter;
+import android.widget.Toolbar;
 
 import java.lang.annotation.Retention;
 import java.lang.annotation.RetentionPolicy;
+import java.util.Map;
 
 /**
- * A window feature at the top of the activity that may display the activity title, navigation
- * modes, and other interactive items.
+ * A primary toolbar within the activity that may display the activity title, application-level
+ * navigation affordances, and other interactive items.
+ *
  * <p>Beginning with Android 3.0 (API level 11), the action bar appears at the top of an
  * activity's window when the activity uses the system's {@link
  * android.R.style#Theme_Holo Holo} theme (or one of its descendant themes), which is the default.
  * You may otherwise add the action bar by calling {@link
  * android.view.Window#requestFeature requestFeature(FEATURE_ACTION_BAR)} or by declaring it in a
  * custom theme with the {@link android.R.styleable#Theme_windowActionBar windowActionBar} property.
- * <p>By default, the action bar shows the application icon on
+ * </p>
+ *
+ * <p>Beginning with Android L (API level 21), the action bar may be represented by any
+ * Toolbar widget within the application layout. The application may signal to the Activity
+ * which Toolbar should be treated as the Activity's action bar. Activities that use this
+ * feature should use one of the supplied <code>.NoActionBar</code> themes, set the
+ * {@link android.R.styleable#Theme_windowActionBar windowActionBar} attribute to <code>false</code>
+ * or otherwise not request the window feature.</p>
+ *
+ * <p>By adjusting the window features requested by the theme and the layouts used for
+ * an Activity's content view, an app can use the standard system action bar on older platform
+ * releases and the newer inline toolbars on newer platform releases. The <code>ActionBar</code>
+ * object obtained from the Activity can be used to control either configuration transparently.</p>
+ *
+ * <p>When using the Holo themes the action bar shows the application icon on
  * the left, followed by the activity title. If your activity has an options menu, you can make
  * select items accessible directly from the action bar as "action items". You can also
  * modify various characteristics of the action bar or remove it completely.</p>
+ *
+ * <p>When using the Quantum themes (default in API 21 or newer) the navigation button
+ * (formerly "Home") takes over the space previously occupied by the application icon.
+ * Apps wishing to express a stronger branding should use their brand colors heavily
+ * in the action bar and other application chrome or use a {@link #setLogo(int) logo}
+ * in place of their standard title text.</p>
+ *
  * <p>From your activity, you can retrieve an instance of {@link ActionBar} by calling {@link
  * android.app.Activity#getActionBar getActionBar()}.</p>
+ *
  * <p>In some cases, the action bar may be overlayed by another bar that enables contextual actions,
  * using an {@link android.view.ActionMode}. For example, when the user selects one or more items in
  * your activity, you can enable an action mode that offers actions specific to the selected
  * items, with a UI that temporarily replaces the action bar. Although the UI may occupy the
  * same space, the {@link android.view.ActionMode} APIs are distinct and independent from those for
- * {@link ActionBar}.
+ * {@link ActionBar}.</p>
+ *
  * <div class="special reference">
  * <h3>Developer Guides</h3>
  * <p>For information about how to use the action bar, including how to add action items, navigation
@@ -904,6 +932,31 @@
      */
     public void setHomeActionContentDescription(int resId) { }
 
+    /** @hide */
+    public void setDefaultDisplayHomeAsUpEnabled(boolean enabled) {
+    }
+
+    /** @hide */
+    public void setShowHideAnimationEnabled(boolean enabled) {
+    }
+
+    /** @hide */
+    public void onConfigurationChanged(Configuration config) {
+    }
+
+    /** @hide */
+    public void dispatchMenuVisibilityChanged(boolean visible) {
+    }
+
+    /** @hide */
+    public void captureSharedElements(Map<String, View> sharedElements) {
+    }
+
+    /** @hide */
+    public ActionMode startActionMode(ActionMode.Callback callback) {
+        return null;
+    }
+
     /**
      * Listener interface for ActionBar navigation events.
      *
@@ -1145,49 +1198,40 @@
      *
      * @attr ref android.R.styleable#ActionBar_LayoutParams_layout_gravity
      */
-    public static class LayoutParams extends MarginLayoutParams {
+    public static class LayoutParams extends ViewGroup.MarginLayoutParams {
         /**
          * Gravity for the view associated with these LayoutParams.
          *
          * @see android.view.Gravity
          */
         @ViewDebug.ExportedProperty(category = "layout", mapping = {
-            @ViewDebug.IntToString(from =  -1,                       to = "NONE"),
-            @ViewDebug.IntToString(from = Gravity.NO_GRAVITY,        to = "NONE"),
-            @ViewDebug.IntToString(from = Gravity.TOP,               to = "TOP"),
-            @ViewDebug.IntToString(from = Gravity.BOTTOM,            to = "BOTTOM"),
-            @ViewDebug.IntToString(from = Gravity.LEFT,              to = "LEFT"),
-            @ViewDebug.IntToString(from = Gravity.RIGHT,             to = "RIGHT"),
-            @ViewDebug.IntToString(from = Gravity.START,             to = "START"),
-            @ViewDebug.IntToString(from = Gravity.END,               to = "END"),
-            @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL,   to = "CENTER_VERTICAL"),
-            @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL,     to = "FILL_VERTICAL"),
-            @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
-            @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL,   to = "FILL_HORIZONTAL"),
-            @ViewDebug.IntToString(from = Gravity.CENTER,            to = "CENTER"),
-            @ViewDebug.IntToString(from = Gravity.FILL,              to = "FILL")
+                @ViewDebug.IntToString(from =  -1,                       to = "NONE"),
+                @ViewDebug.IntToString(from = Gravity.NO_GRAVITY,        to = "NONE"),
+                @ViewDebug.IntToString(from = Gravity.TOP,               to = "TOP"),
+                @ViewDebug.IntToString(from = Gravity.BOTTOM,            to = "BOTTOM"),
+                @ViewDebug.IntToString(from = Gravity.LEFT,              to = "LEFT"),
+                @ViewDebug.IntToString(from = Gravity.RIGHT,             to = "RIGHT"),
+                @ViewDebug.IntToString(from = Gravity.START,             to = "START"),
+                @ViewDebug.IntToString(from = Gravity.END,               to = "END"),
+                @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL,   to = "CENTER_VERTICAL"),
+                @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL,     to = "FILL_VERTICAL"),
+                @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
+                @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL,   to = "FILL_HORIZONTAL"),
+                @ViewDebug.IntToString(from = Gravity.CENTER,            to = "CENTER"),
+                @ViewDebug.IntToString(from = Gravity.FILL,              to = "FILL")
         })
         public int gravity = Gravity.NO_GRAVITY;
 
         public LayoutParams(@NonNull Context c, AttributeSet attrs) {
             super(c, attrs);
-
-            TypedArray a = c.obtainStyledAttributes(attrs,
-                    com.android.internal.R.styleable.ActionBar_LayoutParams);
-            gravity = a.getInt(
-                    com.android.internal.R.styleable.ActionBar_LayoutParams_layout_gravity,
-                    Gravity.NO_GRAVITY);
-            a.recycle();
         }
 
         public LayoutParams(int width, int height) {
             super(width, height);
-            this.gravity = Gravity.CENTER_VERTICAL | Gravity.START;
         }
 
         public LayoutParams(int width, int height, int gravity) {
             super(width, height);
-            this.gravity = gravity;
         }
 
         public LayoutParams(int gravity) {
@@ -1196,12 +1240,14 @@
 
         public LayoutParams(LayoutParams source) {
             super(source);
-
-            this.gravity = source.gravity;
         }
 
         public LayoutParams(ViewGroup.LayoutParams source) {
             super(source);
         }
+
+        public LayoutParams(MarginLayoutParams source) {
+            super(source);
+        }
     }
 }
diff --git a/core/java/android/app/Activity.java b/core/java/android/app/Activity.java
index 20e7311..e8fdcaf 100644
--- a/core/java/android/app/Activity.java
+++ b/core/java/android/app/Activity.java
@@ -23,7 +23,9 @@
 import android.util.ArrayMap;
 import android.util.Pair;
 import android.util.SuperNotCalledException;
-import com.android.internal.app.ActionBarImpl;
+import android.widget.Toolbar;
+import com.android.internal.app.WindowDecorActionBar;
+import com.android.internal.app.ToolbarActionBar;
 import com.android.internal.policy.PolicyManager;
 
 import android.annotation.IntDef;
@@ -723,7 +725,7 @@
     /*package*/ boolean mWindowAdded = false;
     /*package*/ boolean mVisibleFromServer = false;
     /*package*/ boolean mVisibleFromClient = true;
-    /*package*/ ActionBarImpl mActionBar = null;
+    /*package*/ ActionBar mActionBar = null;
     private boolean mEnableDefaultActionBarUp;
 
     private CharSequence mTitle;
@@ -1906,15 +1908,39 @@
      */
     @Nullable
     public ActionBar getActionBar() {
-        initActionBar();
+        initWindowDecorActionBar();
         return mActionBar;
     }
+
+    /**
+     * Set a {@link android.widget.Toolbar Toolbar} to act as the {@link ActionBar} for this
+     * Activity window.
+     *
+     * <p>When set to a non-null value the {@link #getActionBar()} method will return
+     * an {@link ActionBar} object that can be used to control the given toolbar as if it were
+     * a traditional window decor action bar. The toolbar's menu will be populated with the
+     * Activity's options menu and the navigation button will be wired through the standard
+     * {@link android.R.id#home home} menu select action.</p>
+     *
+     * <p>In order to use a Toolbar within the Activity's window content the application
+     * must not request the window feature {@link Window#FEATURE_ACTION_BAR FEATURE_ACTION_BAR}.</p>
+     *
+     * @param actionBar Toolbar to set as the Activity's action bar
+     */
+    public void setActionBar(@Nullable Toolbar actionBar) {
+        if (getActionBar() instanceof WindowDecorActionBar) {
+            throw new IllegalStateException("This Activity already has an action bar supplied " +
+                    "by the window decor. Do not request Window.FEATURE_ACTION_BAR and set " +
+                    "android:windowActionBar to false in your theme to use a Toolbar instead.");
+        }
+        mActionBar = new ToolbarActionBar(actionBar);
+    }
     
     /**
      * Creates a new ActionBar, locates the inflated ActionBarView,
      * initializes the ActionBar with the view, and sets mActionBar.
      */
-    private void initActionBar() {
+    private void initWindowDecorActionBar() {
         Window window = getWindow();
 
         // Initializing the window decor can change window feature flags.
@@ -1925,7 +1951,7 @@
             return;
         }
 
-        mActionBar = new ActionBarImpl(this);
+        mActionBar = new WindowDecorActionBar(this);
         mActionBar.setDefaultDisplayHomeAsUpEnabled(mEnableDefaultActionBarUp);
 
         mWindow.setDefaultIcon(mActivityInfo.getIconResource());
@@ -1943,7 +1969,7 @@
      */
     public void setContentView(int layoutResID) {
         getWindow().setContentView(layoutResID);
-        initActionBar();
+        initWindowDecorActionBar();
     }
 
     /**
@@ -1963,7 +1989,7 @@
      */
     public void setContentView(View view) {
         getWindow().setContentView(view);
-        initActionBar();
+        initWindowDecorActionBar();
     }
 
     /**
@@ -1979,7 +2005,7 @@
      */
     public void setContentView(View view, ViewGroup.LayoutParams params) {
         getWindow().setContentView(view, params);
-        initActionBar();
+        initWindowDecorActionBar();
     }
 
     /**
@@ -1991,7 +2017,7 @@
      */
     public void addContentView(View view, ViewGroup.LayoutParams params) {
         getWindow().addContentView(view, params);
-        initActionBar();
+        initWindowDecorActionBar();
     }
 
     /**
@@ -2636,7 +2662,7 @@
      */
     public boolean onMenuOpened(int featureId, Menu menu) {
         if (featureId == Window.FEATURE_ACTION_BAR) {
-            initActionBar();
+            initWindowDecorActionBar();
             if (mActionBar != null) {
                 mActionBar.dispatchMenuVisibilityChanged(true);
             } else {
@@ -2717,7 +2743,7 @@
                 break;
 
             case Window.FEATURE_ACTION_BAR:
-                initActionBar();
+                initWindowDecorActionBar();
                 mActionBar.dispatchMenuVisibilityChanged(false);
                 break;
         }
@@ -3417,7 +3443,7 @@
     public MenuInflater getMenuInflater() {
         // Make sure that action views can get an appropriate theme.
         if (mMenuInflater == null) {
-            initActionBar();
+            initWindowDecorActionBar();
             if (mActionBar != null) {
                 mMenuInflater = new MenuInflater(mActionBar.getThemedContext(), this);
             } else {
@@ -5139,7 +5165,7 @@
     @Nullable
     @Override
     public ActionMode onWindowStartingActionMode(ActionMode.Callback callback) {
-        initActionBar();
+        initWindowDecorActionBar();
         if (mActionBar != null) {
             return mActionBar.startActionMode(callback);
         }
diff --git a/core/java/android/app/Dialog.java b/core/java/android/app/Dialog.java
index fb96d8d..07583fd 100644
--- a/core/java/android/app/Dialog.java
+++ b/core/java/android/app/Dialog.java
@@ -17,7 +17,7 @@
 package android.app;
 
 import android.content.pm.ApplicationInfo;
-import com.android.internal.app.ActionBarImpl;
+import com.android.internal.app.WindowDecorActionBar;
 import com.android.internal.policy.PolicyManager;
 
 import android.content.ComponentName;
@@ -87,7 +87,7 @@
     final WindowManager mWindowManager;
     Window mWindow;
     View mDecor;
-    private ActionBarImpl mActionBar;
+    private ActionBar mActionBar;
     /**
      * This field should be made private, so it is hidden from the SDK.
      * {@hide}
@@ -280,7 +280,7 @@
             final ApplicationInfo info = mContext.getApplicationInfo();
             mWindow.setDefaultIcon(info.icon);
             mWindow.setDefaultLogo(info.logo);
-            mActionBar = new ActionBarImpl(this);
+            mActionBar = new WindowDecorActionBar(this);
         }
 
         WindowManager.LayoutParams l = mWindow.getAttributes();
diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java
index 1f405a7..e4575e5 100644
--- a/core/java/android/widget/ActionMenuPresenter.java
+++ b/core/java/android/widget/ActionMenuPresenter.java
@@ -640,16 +640,6 @@
         }
 
         @Override
-        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-            if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
-                // Fill available height
-                heightMeasureSpec = MeasureSpec.makeMeasureSpec(
-                        MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.EXACTLY);
-            }
-            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-        }
-
-        @Override
         public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
             super.onInitializeAccessibilityNodeInfo(info);
             info.setCanOpenPopup(true);
diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java
index 32c7086..3975edf 100644
--- a/core/java/android/widget/ActionMenuView.java
+++ b/core/java/android/widget/ActionMenuView.java
@@ -20,6 +20,7 @@
 import android.util.AttributeSet;
 import android.view.Gravity;
 import android.view.Menu;
+import android.view.MenuItem;
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
@@ -27,6 +28,7 @@
 import com.android.internal.view.menu.ActionMenuItemView;
 import com.android.internal.view.menu.MenuBuilder;
 import com.android.internal.view.menu.MenuItemImpl;
+import com.android.internal.view.menu.MenuPresenter;
 import com.android.internal.view.menu.MenuView;
 
 /**
@@ -50,6 +52,8 @@
     private int mMinCellSize;
     private int mGeneratedItemPadding;
 
+    private OnMenuItemClickListener mOnMenuItemClickListener;
+
     public ActionMenuView(Context context) {
         this(context, null);
     }
@@ -78,6 +82,10 @@
         }
     }
 
+    public void setOnMenuItemClickListener(OnMenuItemClickListener listener) {
+        mOnMenuItemClickListener = listener;
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         // If we've been given an exact size to match, apply special formatting during layout.
@@ -96,11 +104,11 @@
             mMenu.onItemsChanged(true);
         }
 
-        if (mFormatItems) {
+        final int childCount = getChildCount();
+        if (mFormatItems && childCount > 0) {
             onMeasureExactFormat(widthMeasureSpec, heightMeasureSpec);
         } else {
             // Previous measurement at exact format may have set margins - reset them.
-            final int childCount = getChildCount();
             for (int i = 0; i < childCount; i++) {
                 final View child = getChildAt(i);
                 final LayoutParams lp = (LayoutParams) child.getLayoutParams();
@@ -559,9 +567,11 @@
         if (mMenu == null) {
             final Context context = getContext();
             mMenu = new MenuBuilder(context);
+            mMenu.setCallback(new MenuBuilderCallback());
             mPresenter = new ActionMenuPresenter(context);
-            mPresenter.initForMenu(context, mMenu);
             mPresenter.setMenuView(this);
+            mPresenter.setCallback(new ActionMenuPresenterCallback());
+            mMenu.addMenuPresenter(mPresenter);
         }
 
         return mMenu;
@@ -591,6 +601,44 @@
         return false;
     }
 
+    /**
+     * Interface responsible for receiving menu item click events if the items themselves
+     * do not have individual item click listeners.
+     */
+    public interface OnMenuItemClickListener {
+        /**
+         * This method will be invoked when a menu item is clicked if the item itself did
+         * not already handle the event.
+         *
+         * @param item {@link MenuItem} that was clicked
+         * @return <code>true</code> if the event was handled, <code>false</code> otherwise.
+         */
+        public boolean onMenuItemClick(MenuItem item);
+    }
+
+    private class MenuBuilderCallback implements MenuBuilder.Callback {
+        @Override
+        public boolean onMenuItemSelected(MenuBuilder menu, MenuItem item) {
+            return mOnMenuItemClickListener != null &&
+                    mOnMenuItemClickListener.onMenuItemClick(item);
+        }
+
+        @Override
+        public void onMenuModeChange(MenuBuilder menu) {
+        }
+    }
+
+    private class ActionMenuPresenterCallback implements ActionMenuPresenter.Callback {
+        @Override
+        public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+        }
+
+        @Override
+        public boolean onOpenSubMenu(MenuBuilder subMenu) {
+            return false;
+        }
+    }
+
     /** @hide */
     public interface ActionMenuChildView {
         public boolean needsDividerBefore();
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
new file mode 100644
index 0000000..075feba
--- /dev/null
+++ b/core/java/android/widget/Toolbar.java
@@ -0,0 +1,1048 @@
+/*
+ * Copyright (C) 2014 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.widget;
+
+import android.annotation.NonNull;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.os.Parcel;
+import android.os.Parcelable;
+import android.text.TextUtils;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+import android.view.ViewDebug;
+import android.view.ViewGroup;
+import com.android.internal.R;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A standard toolbar for use within application content.
+ *
+ * <p>A Toolbar is a generalization of {@link android.app.ActionBar action bars} for use
+ * within application layouts. While an action bar is traditionally part of an
+ * {@link android.app.Activity Activity's} opaque window decor controlled by the framework,
+ * a Toolbar may be placed at any arbitrary level of nesting within a view hierarchy.
+ * An application may choose to designate a Toolbar as the action bar for an Activity
+ * using the {@link android.app.Activity#setActionBar(Toolbar) setActionBar()} method.</p>
+ *
+ * <p>Toolbar supports a more focused feature set than ActionBar. From start to end, a toolbar
+ * may contain a combination of the following optional elements:
+ *
+ * <ul>
+ *     <li><em>A navigation button.</em> This may be an Up arrow, navigation menu toggle, close,
+ *     collapse, done or another glyph of the app's choosing. This button should always be used
+ *     to access other navigational destinations within the container of the Toolbar and
+ *     its signified content or otherwise leave the current context signified by the Toolbar.</li>
+ *     <li><em>A branded logo image.</em> This may extend to the height of the bar and can be
+ *     arbitrarily wide.</li>
+ *     <li><em>A title and subtitle.</em> The title should be a signpost for the Toolbar's current
+ *     position in the navigation hierarchy and the content contained there. The subtitle,
+ *     if present should indicate any extended information about the current content.
+ *     If an app uses a logo image it should strongly consider omitting a title and subtitle.</li>
+ *     <li><em>One or more custom views.</em> The application may add arbitrary child views
+ *     to the Toolbar. They will appear at this position within the layout. If a child view's
+ *     {@link LayoutParams} indicates a {@link Gravity} value of
+ *     {@link Gravity#CENTER_HORIZONTAL CENTER_HORIZONTAL} the view will attempt to center
+ *     within the available space remaining in the Toolbar after all other elements have been
+ *     measured.</li>
+ *     <li><em>An {@link ActionMenuView action menu}.</em> The menu of actions will pin to the
+ *     end of the Toolbar offering a few
+ *     <a href="http://developer.android.com/design/patterns/actionbar.html#ActionButtons">
+ *         frequent, important or typical</a> actions along with an optional overflow menu for
+ *         additional actions.</li>
+ * </ul>
+ * </p>
+ *
+ * <p>In modern Android UIs developers should lean more on a visually distinct color scheme for
+ * toolbars than on their application icon. The use of application icon plus title as a standard
+ * layout is discouraged on API 21 devices and newer.</p>
+ */
+public class Toolbar extends ViewGroup {
+    private ActionMenuView mMenuView;
+    private TextView mTitleTextView;
+    private TextView mSubtitleTextView;
+    private ImageButton mNavButtonView;
+    private ImageView mLogoView;
+
+    private int mTitleTextAppearance;
+    private int mSubtitleTextAppearance;
+    private int mTitleMarginStart;
+    private int mTitleMarginEnd;
+    private int mTitleMarginTop;
+    private int mTitleMarginBottom;
+
+    private int mGravity = Gravity.START | Gravity.CENTER_VERTICAL;
+
+    private CharSequence mTitleText;
+    private CharSequence mSubtitleText;
+
+    // Clear me after use.
+    private final ArrayList<View> mTempViews = new ArrayList<View>();
+
+    private OnMenuItemClickListener mOnMenuItemClickListener;
+
+    private final ActionMenuView.OnMenuItemClickListener mMenuViewItemClickListener =
+            new ActionMenuView.OnMenuItemClickListener() {
+                @Override
+                public boolean onMenuItemClick(MenuItem item) {
+                    if (mOnMenuItemClickListener != null) {
+                        return mOnMenuItemClickListener.onMenuItemClick(item);
+                    }
+                    return false;
+                }
+            };
+
+    public Toolbar(Context context) {
+        this(context, null);
+    }
+
+    public Toolbar(Context context, AttributeSet attrs) {
+        this(context, attrs, com.android.internal.R.attr.toolbarStyle);
+    }
+
+    public Toolbar(Context context, AttributeSet attrs, int defStyleAttr) {
+        this(context, attrs, defStyleAttr, 0);
+    }
+
+    public Toolbar(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
+        super(context, attrs, defStyleAttr, defStyleRes);
+
+        final TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.Toolbar,
+                defStyleAttr, defStyleRes);
+
+        mTitleTextAppearance = a.getResourceId(R.styleable.Toolbar_titleTextAppearance, 0);
+        mSubtitleTextAppearance = a.getResourceId(R.styleable.Toolbar_subtitleTextAppearance, 0);
+        mGravity = a.getInteger(R.styleable.Toolbar_gravity, mGravity);
+        mTitleMarginStart = mTitleMarginEnd = Math.max(0, a.getDimensionPixelOffset(
+                R.styleable.Toolbar_titleMargins, -1));
+
+        final int marginStart = a.getDimensionPixelOffset(R.styleable.Toolbar_titleMarginStart, -1);
+        if (marginStart >= 0) {
+            mTitleMarginStart = marginStart;
+        }
+
+        final int marginEnd = a.getDimensionPixelOffset(R.styleable.Toolbar_titleMarginEnd, -1);
+        if (marginEnd >= 0) {
+            mTitleMarginEnd = marginEnd;
+        }
+
+        final int marginTop = a.getDimensionPixelOffset(R.styleable.Toolbar_titleMarginTop, -1);
+        if (marginTop >= 0) {
+            mTitleMarginTop = marginTop;
+        }
+
+        final int marginBottom = a.getDimensionPixelOffset(R.styleable.Toolbar_titleMarginBottom,
+                -1);
+        if (marginBottom >= 0) {
+            mTitleMarginBottom = marginBottom;
+        }
+
+        final CharSequence title = a.getText(R.styleable.Toolbar_title);
+        if (!TextUtils.isEmpty(title)) {
+            setTitle(title);
+        }
+
+        final CharSequence subtitle = a.getText(R.styleable.Toolbar_subtitle);
+        if (!TextUtils.isEmpty(subtitle)) {
+            setSubtitle(title);
+        }
+        a.recycle();
+    }
+
+    /**
+     * Set a logo drawable from a resource id.
+     *
+     * <p>This drawable should generally take the place of title text. The logo cannot be
+     * clicked. Apps using a logo should also supply a description using
+     * {@link #setLogoDescription(int)}.</p>
+     *
+     * @param resId ID of a drawable resource
+     */
+    public void setLogo(int resId) {
+        setLogo(getContext().getDrawable(resId));
+    }
+
+    /**
+     * Set a logo drawable.
+     *
+     * <p>This drawable should generally take the place of title text. The logo cannot be
+     * clicked. Apps using a logo should also supply a description using
+     * {@link #setLogoDescription(int)}.</p>
+     *
+     * @param drawable Drawable to use as a logo
+     */
+    public void setLogo(Drawable drawable) {
+        if (drawable != null) {
+            if (mLogoView == null) {
+                mLogoView = new ImageView(getContext());
+            }
+            if (mLogoView.getParent() == null) {
+                addSystemView(mLogoView);
+            }
+        } else if (mLogoView != null && mLogoView.getParent() != null) {
+            removeView(mLogoView);
+        }
+        if (mLogoView != null) {
+            mLogoView.setImageDrawable(drawable);
+        }
+    }
+
+    /**
+     * Return the current logo drawable.
+     *
+     * @return The current logo drawable
+     * @see #setLogo(int)
+     * @see #setLogo(android.graphics.drawable.Drawable)
+     */
+    public Drawable getLogo() {
+        return mLogoView != null ? mLogoView.getDrawable() : null;
+    }
+
+    /**
+     * Set a description of the toolbar's logo.
+     *
+     * <p>This description will be used for accessibility or other similar descriptions
+     * of the UI.</p>
+     *
+     * @param resId String resource id
+     */
+    public void setLogoDescription(int resId) {
+        setLogoDescription(getContext().getText(resId));
+    }
+
+    /**
+     * Set a description of the toolbar's logo.
+     *
+     * <p>This description will be used for accessibility or other similar descriptions
+     * of the UI.</p>
+     *
+     * @param description Description to set
+     */
+    public void setLogoDescription(CharSequence description) {
+        if (!TextUtils.isEmpty(description) && mLogoView == null) {
+            mLogoView = new ImageView(getContext());
+        }
+        if (mLogoView != null) {
+            mLogoView.setContentDescription(description);
+        }
+    }
+
+    /**
+     * Return the description of the toolbar's logo.
+     *
+     * @return A description of the logo
+     */
+    public CharSequence getLogoDescription() {
+        return mLogoView != null ? mLogoView.getContentDescription() : null;
+    }
+
+    /**
+     * Return the current title displayed in the toolbar.
+     *
+     * @return The current title
+     */
+    public CharSequence getTitle() {
+        return mTitleText;
+    }
+
+    /**
+     * Set the title of this toolbar.
+     *
+     * <p>A title should be used as the anchor for a section of content. It should
+     * describe or name the content being viewed.</p>
+     *
+     * @param resId Resource ID of a string to set as the title
+     */
+    public void setTitle(int resId) {
+        setTitle(getContext().getText(resId));
+    }
+
+    /**
+     * Set the title of this toolbar.
+     *
+     * <p>A title should be used as the anchor for a section of content. It should
+     * describe or name the content being viewed.</p>
+     *
+     * @param title Title to set
+     */
+    public void setTitle(CharSequence title) {
+        if (!TextUtils.isEmpty(title)) {
+            if (mTitleTextView == null) {
+                final Context context = getContext();
+                mTitleTextView = new TextView(context);
+                mTitleTextView.setTextAppearance(context, mTitleTextAppearance);
+            }
+            if (mTitleTextView.getParent() == null) {
+                addSystemView(mTitleTextView);
+            }
+        } else if (mTitleTextView != null && mTitleTextView.getParent() != null) {
+            removeView(mTitleTextView);
+        }
+        if (mTitleTextView != null) {
+            mTitleTextView.setText(title);
+        }
+        mTitleText = title;
+    }
+
+    /**
+     * Return the subtitle of this toolbar.
+     *
+     * @return The current subtitle
+     */
+    public CharSequence getSubtitle() {
+        return mSubtitleText;
+    }
+
+    /**
+     * Set the subtitle of this toolbar.
+     *
+     * <p>Subtitles should express extended information about the current content.</p>
+     *
+     * @param resId String resource ID
+     */
+    public void setSubtitle(int resId) {
+        setSubtitle(getContext().getText(resId));
+    }
+
+    /**
+     * Set the subtitle of this toolbar.
+     *
+     * <p>Subtitles should express extended information about the current content.</p>
+     *
+     * @param subtitle Subtitle to set
+     */
+    public void setSubtitle(CharSequence subtitle) {
+        if (!TextUtils.isEmpty(subtitle)) {
+            if (mSubtitleTextView == null) {
+                final Context context = getContext();
+                mSubtitleTextView = new TextView(context);
+                mSubtitleTextView.setTextAppearance(context, mSubtitleTextAppearance);
+            }
+            if (mSubtitleTextView.getParent() == null) {
+                addSystemView(mSubtitleTextView);
+            }
+        } else if (mSubtitleTextView != null && mSubtitleTextView.getParent() != null) {
+            removeView(mSubtitleTextView);
+        }
+        if (mSubtitleTextView != null) {
+            mSubtitleTextView.setText(subtitle);
+        }
+        mSubtitleText = subtitle;
+    }
+
+    /**
+     * Set the icon to use for the toolbar's navigation button.
+     *
+     * <p>The navigation button appears at the start of the toolbar if present. Setting an icon
+     * will make the navigation button visible.</p>
+     *
+     * <p>If you use a navigation icon you should also set a description for its action using
+     * {@link #setNavigationDescription(int)}. This is used for accessibility and tooltips.</p>
+     *
+     * @param resId Resource ID of a drawable to set
+     */
+    public void setNavigationIcon(int resId) {
+        setNavigationIcon(getContext().getDrawable(resId));
+    }
+
+    /**
+     * Set the icon to use for the toolbar's navigation button.
+     *
+     * <p>The navigation button appears at the start of the toolbar if present. Setting an icon
+     * will make the navigation button visible.</p>
+     *
+     * <p>If you use a navigation icon you should also set a description for its action using
+     * {@link #setNavigationDescription(int)}. This is used for accessibility and tooltips.</p>
+     *
+     * @param icon Drawable to set
+     */
+    public void setNavigationIcon(Drawable icon) {
+        if (icon != null) {
+            ensureNavButtonView();
+            if (mNavButtonView.getParent() == null) {
+                addSystemView(mNavButtonView);
+            }
+        } else if (mNavButtonView != null && mNavButtonView.getParent() != null) {
+            removeView(mNavButtonView);
+        }
+        if (mNavButtonView != null) {
+            mNavButtonView.setImageDrawable(icon);
+        }
+    }
+
+    /**
+     * Return the current drawable used as the navigation icon.
+     *
+     * @return The navigation icon drawable
+     */
+    public Drawable getNavigationIcon() {
+        return mNavButtonView != null ? mNavButtonView.getDrawable() : null;
+    }
+
+    /**
+     * Set a description for the navigation button.
+     *
+     * <p>This description string is used for accessibility, tooltips and other facilities
+     * to improve discoverability.</p>
+     *
+     * @param resId Resource ID of a string to set
+     */
+    public void setNavigationDescription(int resId) {
+        setNavigationDescription(getContext().getText(resId));
+    }
+
+    /**
+     * Set a description for the navigation button.
+     *
+     * <p>This description string is used for accessibility, tooltips and other facilities
+     * to improve discoverability.</p>
+     *
+     * @param description String to set as the description
+     */
+    public void setNavigationDescription(CharSequence description) {
+        if (!TextUtils.isEmpty(description)) {
+            ensureNavButtonView();
+        }
+        if (mNavButtonView != null) {
+            mNavButtonView.setContentDescription(description);
+        }
+    }
+
+    /**
+     * Set a listener to respond to navigation events.
+     *
+     * <p>This listener will be called whenever the user clicks the navigation button
+     * at the start of the toolbar. An icon must be set for the navigation button to appear.</p>
+     *
+     * @param listener Listener to set
+     * @see #setNavigationIcon(android.graphics.drawable.Drawable)
+     */
+    public void setNavigationOnClickListener(OnClickListener listener) {
+        ensureNavButtonView();
+        mNavButtonView.setOnClickListener(listener);
+    }
+
+    /**
+     * Return the Menu shown in the toolbar.
+     *
+     * <p>Applications that wish to populate the toolbar's menu can do so from here. To use
+     * an XML menu resource, use {@link #inflateMenu(int)}.</p>
+     *
+     * @return The toolbar's Menu
+     */
+    public Menu getMenu() {
+        if (mMenuView == null) {
+            mMenuView = new ActionMenuView(getContext());
+            mMenuView.setOnMenuItemClickListener(mMenuViewItemClickListener);
+            addSystemView(mMenuView);
+        }
+        return mMenuView.getMenu();
+    }
+
+    private MenuInflater getMenuInflater() {
+        return new MenuInflater(getContext());
+    }
+
+    /**
+     * Inflate a menu resource into this toolbar.
+     *
+     * <p>Inflate an XML menu resource into this toolbar. Existing items in the menu will not
+     * be modified or removed.</p>
+     *
+     * @param resId ID of a menu resource to inflate
+     */
+    public void inflateMenu(int resId) {
+        getMenuInflater().inflate(resId, getMenu());
+    }
+
+    /**
+     * Set a listener to respond to menu item click events.
+     *
+     * <p>This listener will be invoked whenever a user selects a menu item from
+     * the action buttons presented at the end of the toolbar or the associated overflow.</p>
+     *
+     * @param listener Listener to set
+     */
+    public void setOnMenuItemClickListener(OnMenuItemClickListener listener) {
+        mOnMenuItemClickListener = listener;
+    }
+
+    private void ensureNavButtonView() {
+        if (mNavButtonView == null) {
+            mNavButtonView = new ImageButton(getContext(), null, R.attr.borderlessButtonStyle);
+        }
+    }
+
+    private void addSystemView(View v) {
+        final LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
+                LayoutParams.WRAP_CONTENT);
+        lp.mViewType = LayoutParams.SYSTEM;
+        addView(v, lp);
+    }
+
+    @Override
+    protected Parcelable onSaveInstanceState() {
+        SavedState state = new SavedState(super.onSaveInstanceState());
+        return state;
+    }
+
+    @Override
+    protected void onRestoreInstanceState(Parcelable state) {
+        final SavedState ss = (SavedState) state;
+        super.onRestoreInstanceState(ss.getSuperState());
+    }
+
+    @Override
+    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        int width = 0;
+        int height = 0;
+        int childState = 0;
+
+        // System views measure first.
+
+        if (shouldLayout(mNavButtonView)) {
+            measureChildWithMargins(mNavButtonView, widthMeasureSpec, width, heightMeasureSpec, 0);
+            width += mNavButtonView.getMeasuredWidth() + getHorizontalMargins(mNavButtonView);
+            height = Math.max(height, mNavButtonView.getMeasuredHeight() +
+                    getVerticalMargins(mNavButtonView));
+            childState = combineMeasuredStates(childState, mNavButtonView.getMeasuredState());
+        }
+
+        if (shouldLayout(mMenuView)) {
+            measureChildWithMargins(mMenuView, widthMeasureSpec, width, heightMeasureSpec, 0);
+            width += mMenuView.getMeasuredWidth() + getHorizontalMargins(mMenuView);
+            height = Math.max(height, mMenuView.getMeasuredHeight() +
+                    getVerticalMargins(mMenuView));
+            childState = combineMeasuredStates(childState, mMenuView.getMeasuredState());
+        }
+
+        if (shouldLayout(mLogoView)) {
+            measureChildWithMargins(mLogoView, widthMeasureSpec, width, heightMeasureSpec, 0);
+            width += mLogoView.getMeasuredWidth() + getHorizontalMargins(mLogoView);
+            height = Math.max(height, mLogoView.getMeasuredHeight() +
+                    getVerticalMargins(mLogoView));
+            childState = combineMeasuredStates(childState, mLogoView.getMeasuredState());
+        }
+
+        int titleWidth = 0;
+        int titleHeight = 0;
+        final int titleVertMargins = mTitleMarginTop + mTitleMarginBottom;
+        final int titleHorizMargins = mTitleMarginStart + mTitleMarginEnd;
+        if (shouldLayout(mTitleTextView)) {
+            measureChildWithMargins(mTitleTextView, widthMeasureSpec, width + titleHorizMargins,
+                    heightMeasureSpec, titleVertMargins);
+            titleWidth = mTitleTextView.getMeasuredWidth() + getHorizontalMargins(mTitleTextView);
+            titleHeight = mTitleTextView.getMeasuredHeight() + getVerticalMargins(mTitleTextView);
+            childState = combineMeasuredStates(childState, mTitleTextView.getMeasuredState());
+        }
+        if (shouldLayout(mSubtitleTextView)) {
+            measureChildWithMargins(mSubtitleTextView, widthMeasureSpec, width + titleHorizMargins,
+                    heightMeasureSpec, titleHeight + titleVertMargins);
+            titleWidth = Math.max(titleWidth, mSubtitleTextView.getMeasuredWidth() +
+                    getHorizontalMargins(mSubtitleTextView));
+            titleHeight += mSubtitleTextView.getMeasuredHeight() +
+                    getVerticalMargins(mSubtitleTextView);
+            childState = combineMeasuredStates(childState, mSubtitleTextView.getMeasuredState());
+        }
+
+        width += titleWidth;
+        height = Math.max(height, titleHeight);
+
+        final int childCount = getChildCount();
+        for (int i = 0; i < childCount; i++) {
+            final View child = getChildAt(i);
+            final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+            if (lp.mViewType == LayoutParams.SYSTEM || !shouldLayout(child)) {
+                // We already got all system views above. Skip them and GONE views.
+                continue;
+            }
+
+            measureChildWithMargins(child, widthMeasureSpec, width, heightMeasureSpec, 0);
+            width += child.getMeasuredWidth() + getHorizontalMargins(child);
+            height = Math.max(height, child.getMeasuredHeight() + getVerticalMargins(child));
+            childState = combineMeasuredStates(childState, child.getMeasuredState());
+        }
+
+        // Measurement already took padding into account for available space for the children,
+        // add it in for the final size.
+        width += getPaddingLeft() + getPaddingRight();
+        height += getPaddingTop() + getPaddingBottom();
+
+        final int measuredWidth = resolveSizeAndState(
+                Math.max(width, getSuggestedMinimumWidth()),
+                widthMeasureSpec, childState & MEASURED_STATE_MASK);
+        final int measuredHeight = resolveSizeAndState(
+                Math.max(height, getSuggestedMinimumHeight()),
+                heightMeasureSpec, childState << MEASURED_HEIGHT_STATE_SHIFT);
+        setMeasuredDimension(measuredWidth, measuredHeight);
+    }
+
+    @Override
+    protected void onLayout(boolean changed, int l, int t, int r, int b) {
+        final boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+        final int width = getWidth();
+        final int height = getHeight();
+        final int paddingLeft = getPaddingLeft();
+        final int paddingRight = getPaddingRight();
+        final int paddingTop = getPaddingTop();
+        final int paddingBottom = getPaddingBottom();
+        int left = paddingLeft;
+        int right = width - paddingRight;
+
+        if (shouldLayout(mNavButtonView)) {
+            if (isRtl) {
+                right = layoutChildRight(mNavButtonView, right);
+            } else {
+                left = layoutChildLeft(mNavButtonView, left);
+            }
+        }
+
+        if (shouldLayout(mMenuView)) {
+            if (isRtl) {
+                left = layoutChildLeft(mMenuView, left);
+            } else {
+                right = layoutChildRight(mMenuView, right);
+            }
+        }
+
+        if (shouldLayout(mLogoView)) {
+            if (isRtl) {
+                right = layoutChildRight(mLogoView, right);
+            } else {
+                left = layoutChildLeft(mLogoView, left);
+            }
+        }
+
+        final boolean layoutTitle = shouldLayout(mTitleTextView);
+        final boolean layoutSubtitle = shouldLayout(mSubtitleTextView);
+        int titleHeight = 0;
+        if (layoutTitle) {
+            final LayoutParams lp = (LayoutParams) mTitleTextView.getLayoutParams();
+            titleHeight += lp.topMargin + mTitleTextView.getMeasuredHeight() + lp.bottomMargin;
+        }
+        if (layoutSubtitle) {
+            final LayoutParams lp = (LayoutParams) mSubtitleTextView.getLayoutParams();
+            titleHeight += lp.bottomMargin + mTitleTextView.getMeasuredHeight() + lp.bottomMargin;
+        }
+
+        if (layoutTitle || layoutSubtitle) {
+            int titleTop;
+            switch (mGravity & Gravity.VERTICAL_GRAVITY_MASK) {
+                case Gravity.TOP:
+                    titleTop = getPaddingTop();
+                    break;
+                default:
+                case Gravity.CENTER_VERTICAL:
+                    final View child = layoutTitle ? mTitleTextView : mSubtitleTextView;
+                    final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                    final int space = height - paddingTop - paddingBottom;
+                    int spaceAbove = (space - titleHeight) / 2;
+                    if (spaceAbove < lp.topMargin + mTitleMarginTop) {
+                        spaceAbove = lp.topMargin + mTitleMarginTop;
+                    } else {
+                        final int spaceBelow = height - paddingBottom - titleHeight -
+                                spaceAbove - paddingTop;
+                        if (spaceBelow < lp.bottomMargin + mTitleMarginBottom) {
+                            spaceAbove = Math.max(0, spaceAbove -
+                                    (lp.bottomMargin + mTitleMarginBottom - spaceBelow));
+                        }
+                    }
+                    titleTop = paddingTop + spaceAbove;
+                    break;
+                case Gravity.BOTTOM:
+                    titleTop = height - paddingBottom - titleHeight;
+                    break;
+            }
+            if (isRtl) {
+                int titleRight = right;
+                int subtitleRight = right;
+                titleTop += mTitleMarginTop;
+                if (layoutTitle) {
+                    final LayoutParams lp = (LayoutParams) mTitleTextView.getLayoutParams();
+                    titleRight -= lp.rightMargin + mTitleMarginStart;
+                    titleTop += lp.topMargin;
+                    final int titleLeft = titleRight - mTitleTextView.getMeasuredWidth();
+                    final int titleBottom = titleTop + mTitleTextView.getMeasuredHeight();
+                    mTitleTextView.layout(titleLeft, titleTop, titleRight, titleBottom);
+                    titleRight = titleLeft - lp.leftMargin - mTitleMarginEnd;
+                    titleTop = titleBottom + lp.bottomMargin;
+                }
+                if (layoutSubtitle) {
+                    final LayoutParams lp = (LayoutParams) mSubtitleTextView.getLayoutParams();
+                    subtitleRight -= lp.rightMargin + mTitleMarginStart;
+                    titleTop += lp.topMargin;
+                    final int subtitleLeft = subtitleRight - mSubtitleTextView.getMeasuredWidth();
+                    final int subtitleBottom = titleTop + mSubtitleTextView.getMeasuredHeight();
+                    mSubtitleTextView.layout(subtitleLeft, titleTop, subtitleRight, subtitleBottom);
+                    subtitleRight = subtitleRight - lp.leftMargin - mTitleMarginEnd;
+                    titleTop = subtitleBottom + lp.bottomMargin;
+                }
+                right = Math.max(titleRight, subtitleRight);
+            } else {
+                int titleLeft = left;
+                int subtitleLeft = left;
+                titleTop += mTitleMarginTop;
+                if (layoutTitle) {
+                    final LayoutParams lp = (LayoutParams) mTitleTextView.getLayoutParams();
+                    titleLeft += lp.leftMargin + mTitleMarginStart;
+                    titleTop += lp.topMargin;
+                    final int titleRight = titleLeft + mTitleTextView.getMeasuredWidth();
+                    final int titleBottom = titleTop + mTitleTextView.getMeasuredHeight();
+                    mTitleTextView.layout(titleLeft, titleTop, titleRight, titleBottom);
+                    titleLeft = titleRight + lp.rightMargin + mTitleMarginEnd;
+                    titleTop = titleBottom + lp.bottomMargin;
+                }
+                if (layoutSubtitle) {
+                    final LayoutParams lp = (LayoutParams) mSubtitleTextView.getLayoutParams();
+                    subtitleLeft += lp.leftMargin + mTitleMarginStart;
+                    titleTop += lp.topMargin;
+                    final int subtitleRight = subtitleLeft + mSubtitleTextView.getMeasuredWidth();
+                    final int subtitleBottom = titleTop + mSubtitleTextView.getMeasuredHeight();
+                    mSubtitleTextView.layout(subtitleLeft, titleTop, subtitleRight, subtitleBottom);
+                    subtitleLeft = subtitleRight + lp.rightMargin + mTitleMarginEnd;
+                    titleTop = subtitleBottom + lp.bottomMargin;
+                }
+                left = Math.max(titleLeft, subtitleLeft);
+            }
+        }
+
+        // Get all remaining children sorted for layout. This is all prepared
+        // such that absolute layout direction can be used below.
+
+        addCustomViewsWithGravity(mTempViews, Gravity.LEFT);
+        final int leftViewsCount = mTempViews.size();
+        for (int i = 0; i < leftViewsCount; i++) {
+            left = layoutChildLeft(getChildAt(i), left);
+        }
+
+        addCustomViewsWithGravity(mTempViews, Gravity.RIGHT);
+        final int rightViewsCount = mTempViews.size();
+        for (int i = 0; i < rightViewsCount; i++) {
+            right = layoutChildRight(getChildAt(i), right);
+        }
+
+        // Centered views try to center with respect to the whole bar, but views pinned
+        // to the left or right can push the mass of centered views to one side or the other.
+        addCustomViewsWithGravity(mTempViews, Gravity.CENTER);
+        final int centerViewsWidth = getViewListMeasuredWidth(mTempViews);
+        final int parentCenter = paddingLeft + (width - paddingLeft - paddingRight) / 2;
+        final int halfCenterViewsWidth = centerViewsWidth / 2;
+        int centerLeft = parentCenter - halfCenterViewsWidth;
+        final int centerRight = centerLeft + centerViewsWidth;
+        if (centerLeft < left) {
+            centerLeft = left;
+        } else if (centerRight > right) {
+            centerLeft -= centerRight - right;
+        }
+
+        final int centerViewsCount = mTempViews.size();
+        for (int i = 0; i < centerViewsCount; i++) {
+            centerLeft = layoutChildLeft(getChildAt(i), centerLeft);
+        }
+        mTempViews.clear();
+    }
+
+    private int getViewListMeasuredWidth(List<View> views) {
+        int width = 0;
+        final int count = views.size();
+        for (int i = 0; i < count; i++) {
+            final View v = views.get(i);
+            final LayoutParams lp = (LayoutParams) v.getLayoutParams();
+            width += lp.leftMargin + v.getMeasuredWidth() + lp.rightMargin;
+        }
+        return width;
+    }
+
+    private int layoutChildLeft(View child, int left) {
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+        left += lp.leftMargin;
+        int top = getChildTop(child);
+        child.layout(left, top, left + child.getMeasuredWidth(), top + child.getMeasuredHeight());
+        left += lp.rightMargin;
+        return left;
+    }
+
+    private int layoutChildRight(View child, int right) {
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+        right -= lp.rightMargin;
+        int top = getChildTop(child);
+        child.layout(right - child.getMeasuredWidth(), top, right, top + child.getMeasuredHeight());
+        right -= lp.leftMargin;
+        return right;
+    }
+
+    private int getChildTop(View child) {
+        final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+        switch (getChildVerticalGravity(lp.gravity)) {
+            case Gravity.TOP:
+                return getPaddingTop();
+
+            case Gravity.BOTTOM:
+                return getPaddingBottom() - child.getMeasuredHeight() - lp.bottomMargin;
+
+            default:
+            case Gravity.CENTER_VERTICAL:
+                final int paddingTop = getPaddingTop();
+                final int paddingBottom = getPaddingBottom();
+                final int height = getHeight();
+                final int childHeight = child.getMeasuredHeight();
+                final int space = height - paddingTop - paddingBottom;
+                int spaceAbove = (space - childHeight) / 2;
+                if (spaceAbove < lp.topMargin) {
+                    spaceAbove = lp.topMargin;
+                } else {
+                    final int spaceBelow = height - paddingBottom - childHeight -
+                            spaceAbove - paddingTop;
+                    if (spaceBelow < lp.bottomMargin) {
+                        spaceAbove = Math.max(0, spaceAbove - (lp.bottomMargin - spaceBelow));
+                    }
+                }
+                return paddingTop + spaceAbove;
+        }
+    }
+
+    private int getChildVerticalGravity(int gravity) {
+        final int vgrav = gravity & Gravity.VERTICAL_GRAVITY_MASK;
+        switch (vgrav) {
+            case Gravity.TOP:
+            case Gravity.BOTTOM:
+            case Gravity.CENTER_VERTICAL:
+                return vgrav;
+            default:
+                return mGravity & Gravity.VERTICAL_GRAVITY_MASK;
+        }
+    }
+
+    /**
+     * Prepare a list of non-SYSTEM child views. If the layout direction is RTL
+     * this will be in reverse child order.
+     *
+     * @param views List to populate. It will be cleared before use.
+     * @param gravity Horizontal gravity to match against
+     */
+    private void addCustomViewsWithGravity(List<View> views, int gravity) {
+        final boolean isRtl = getLayoutDirection() == LAYOUT_DIRECTION_RTL;
+        final int childCount = getChildCount();
+        final int absGrav = Gravity.getAbsoluteGravity(gravity, getLayoutDirection());
+
+        views.clear();
+
+        if (isRtl) {
+            for (int i = childCount - 1; i >= 0; i--) {
+                final View child = getChildAt(i);
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                if (lp.mViewType != LayoutParams.SYSTEM && shouldLayout(child) &&
+                        getChildHorizontalGravity(lp.gravity) == absGrav) {
+                    views.add(child);
+                }
+
+            }
+        } else {
+            for (int i = 0; i < childCount; i++) {
+                final View child = getChildAt(i);
+                final LayoutParams lp = (LayoutParams) child.getLayoutParams();
+                if (lp.mViewType != LayoutParams.SYSTEM && shouldLayout(child) &&
+                        getChildHorizontalGravity(lp.gravity) == absGrav) {
+                    views.add(child);
+                }
+            }
+        }
+    }
+
+    private int getChildHorizontalGravity(int gravity) {
+        final int ld = getLayoutDirection();
+        final int absGrav = Gravity.getAbsoluteGravity(gravity, ld);
+        final int hGrav = absGrav & Gravity.HORIZONTAL_GRAVITY_MASK;
+        switch (hGrav) {
+            case Gravity.LEFT:
+            case Gravity.RIGHT:
+            case Gravity.CENTER_HORIZONTAL:
+                return hGrav;
+            default:
+                return ld == LAYOUT_DIRECTION_RTL ? Gravity.RIGHT : Gravity.LEFT;
+        }
+    }
+
+    private boolean shouldLayout(View view) {
+        return view != null && view.getParent() == this && view.getVisibility() != GONE;
+    }
+
+    private int getHorizontalMargins(View v) {
+        final MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams();
+        return mlp.getMarginStart() + mlp.getMarginEnd();
+    }
+
+    private int getVerticalMargins(View v) {
+        final MarginLayoutParams mlp = (MarginLayoutParams) v.getLayoutParams();
+        return mlp.topMargin + mlp.bottomMargin;
+    }
+
+    @Override
+    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return super.generateLayoutParams(attrs);
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+        if (p instanceof LayoutParams) {
+            return new LayoutParams((LayoutParams) p);
+        } else if (p instanceof MarginLayoutParams) {
+            return new LayoutParams((MarginLayoutParams) p);
+        } else {
+            return new LayoutParams(p);
+        }
+    }
+
+    @Override
+    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
+        return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
+    }
+
+    @Override
+    protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
+        return super.checkLayoutParams(p) && p instanceof LayoutParams;
+    }
+
+    private static boolean isCustomView(View child) {
+        return ((LayoutParams) child.getLayoutParams()).mViewType == LayoutParams.CUSTOM;
+    }
+
+    /**
+     * Interface responsible for receiving menu item click events if the items themselves
+     * do not have individual item click listeners.
+     */
+    public interface OnMenuItemClickListener {
+        /**
+         * This method will be invoked when a menu item is clicked if the item itself did
+         * not already handle the event.
+         *
+         * @param item {@link MenuItem} that was clicked
+         * @return <code>true</code> if the event was handled, <code>false</code> otherwise.
+         */
+        public boolean onMenuItemClick(MenuItem item);
+    }
+
+    /**
+     * Layout information for child views of Toolbars.
+     *
+     * @attr ref android.R.styleable#Toolbar_LayoutParams_layout_gravity
+     */
+    public static class LayoutParams extends MarginLayoutParams {
+        /**
+         * Gravity for the view associated with these LayoutParams.
+         *
+         * @see android.view.Gravity
+         */
+        @ViewDebug.ExportedProperty(category = "layout", mapping = {
+                @ViewDebug.IntToString(from =  -1,                       to = "NONE"),
+                @ViewDebug.IntToString(from = Gravity.NO_GRAVITY,        to = "NONE"),
+                @ViewDebug.IntToString(from = Gravity.TOP,               to = "TOP"),
+                @ViewDebug.IntToString(from = Gravity.BOTTOM,            to = "BOTTOM"),
+                @ViewDebug.IntToString(from = Gravity.LEFT,              to = "LEFT"),
+                @ViewDebug.IntToString(from = Gravity.RIGHT,             to = "RIGHT"),
+                @ViewDebug.IntToString(from = Gravity.START,             to = "START"),
+                @ViewDebug.IntToString(from = Gravity.END,               to = "END"),
+                @ViewDebug.IntToString(from = Gravity.CENTER_VERTICAL,   to = "CENTER_VERTICAL"),
+                @ViewDebug.IntToString(from = Gravity.FILL_VERTICAL,     to = "FILL_VERTICAL"),
+                @ViewDebug.IntToString(from = Gravity.CENTER_HORIZONTAL, to = "CENTER_HORIZONTAL"),
+                @ViewDebug.IntToString(from = Gravity.FILL_HORIZONTAL,   to = "FILL_HORIZONTAL"),
+                @ViewDebug.IntToString(from = Gravity.CENTER,            to = "CENTER"),
+                @ViewDebug.IntToString(from = Gravity.FILL,              to = "FILL")
+        })
+        public int gravity = Gravity.NO_GRAVITY;
+
+        static final int CUSTOM = 0;
+        static final int SYSTEM = 1;
+
+        int mViewType = CUSTOM;
+
+        public LayoutParams(@NonNull Context c, AttributeSet attrs) {
+            super(c, attrs);
+
+            TypedArray a = c.obtainStyledAttributes(attrs,
+                    com.android.internal.R.styleable.Toolbar_LayoutParams);
+            gravity = a.getInt(
+                    com.android.internal.R.styleable.Toolbar_LayoutParams_layout_gravity,
+                    Gravity.NO_GRAVITY);
+            a.recycle();
+        }
+
+        public LayoutParams(int width, int height) {
+            super(width, height);
+            this.gravity = Gravity.CENTER_VERTICAL | Gravity.START;
+        }
+
+        public LayoutParams(int width, int height, int gravity) {
+            super(width, height);
+            this.gravity = gravity;
+        }
+
+        public LayoutParams(int gravity) {
+            this(WRAP_CONTENT, MATCH_PARENT, gravity);
+        }
+
+        public LayoutParams(LayoutParams source) {
+            super(source);
+
+            this.gravity = source.gravity;
+        }
+
+        public LayoutParams(MarginLayoutParams source) {
+            super(source);
+        }
+
+        public LayoutParams(ViewGroup.LayoutParams source) {
+            super(source);
+        }
+    }
+
+    static class SavedState extends BaseSavedState {
+        public SavedState(Parcel source) {
+            super(source);
+        }
+
+        public SavedState(Parcelable superState) {
+            super(superState);
+        }
+
+        @Override
+        public void writeToParcel(Parcel out, int flags) {
+            super.writeToParcel(out, flags);
+        }
+
+        public static final Creator<SavedState> CREATOR = new Creator<SavedState>() {
+
+            @Override
+            public SavedState createFromParcel(Parcel source) {
+                return new SavedState(source);
+            }
+
+            @Override
+            public SavedState[] newArray(int size) {
+                return new SavedState[size];
+            }
+        };
+    }
+}
diff --git a/core/java/com/android/internal/app/ToolbarActionBar.java b/core/java/com/android/internal/app/ToolbarActionBar.java
new file mode 100644
index 0000000..34156e5
--- /dev/null
+++ b/core/java/com/android/internal/app/ToolbarActionBar.java
@@ -0,0 +1,452 @@
+/*
+ * Copyright (C) 2014 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.annotation.Nullable;
+import android.app.ActionBar;
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.drawable.Drawable;
+import android.view.ActionMode;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.widget.SpinnerAdapter;
+import android.widget.Toolbar;
+
+import java.util.ArrayList;
+import java.util.Map;
+
+public class ToolbarActionBar extends ActionBar {
+    private Toolbar mToolbar;
+    private View mCustomView;
+
+    private int mDisplayOptions;
+
+    private int mNavResId;
+    private int mIconResId;
+    private int mLogoResId;
+    private Drawable mNavDrawable;
+    private Drawable mIconDrawable;
+    private Drawable mLogoDrawable;
+    private int mTitleResId;
+    private int mSubtitleResId;
+    private CharSequence mTitle;
+    private CharSequence mSubtitle;
+
+    private boolean mLastMenuVisibility;
+    private ArrayList<OnMenuVisibilityListener> mMenuVisibilityListeners =
+            new ArrayList<OnMenuVisibilityListener>();
+
+    public ToolbarActionBar(Toolbar toolbar) {
+        mToolbar = toolbar;
+    }
+
+    @Override
+    public void setCustomView(View view) {
+        setCustomView(view, new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
+    }
+
+    @Override
+    public void setCustomView(View view, LayoutParams layoutParams) {
+        if (mCustomView != null) {
+            mToolbar.removeView(mCustomView);
+        }
+        mCustomView = view;
+        if (view != null) {
+            mToolbar.addView(view, generateLayoutParams(layoutParams));
+        }
+    }
+
+    private Toolbar.LayoutParams generateLayoutParams(LayoutParams lp) {
+        final Toolbar.LayoutParams result = new Toolbar.LayoutParams(lp);
+        result.gravity = lp.gravity;
+        return result;
+    }
+
+    @Override
+    public void setCustomView(int resId) {
+        final LayoutInflater inflater = LayoutInflater.from(mToolbar.getContext());
+        setCustomView(inflater.inflate(resId, mToolbar, false));
+    }
+
+    @Override
+    public void setIcon(int resId) {
+        mIconResId = resId;
+        mIconDrawable = null;
+        updateToolbarLogo();
+    }
+
+    @Override
+    public void setIcon(Drawable icon) {
+        mIconResId = 0;
+        mIconDrawable = icon;
+        updateToolbarLogo();
+    }
+
+    @Override
+    public void setLogo(int resId) {
+        mLogoResId = resId;
+        mLogoDrawable = null;
+        updateToolbarLogo();
+    }
+
+    @Override
+    public void setLogo(Drawable logo) {
+        mLogoResId = 0;
+        mLogoDrawable = logo;
+        updateToolbarLogo();
+    }
+
+    private void updateToolbarLogo() {
+        Drawable drawable = null;
+        if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_HOME) != 0) {
+            final int resId;
+            if ((mDisplayOptions & ActionBar.DISPLAY_USE_LOGO) != 0) {
+                resId = mLogoResId;
+                drawable = mLogoDrawable;
+            } else {
+                resId = mIconResId;
+                drawable = mIconDrawable;
+            }
+            if (resId != 0) {
+                drawable = mToolbar.getContext().getDrawable(resId);
+            }
+        }
+        mToolbar.setLogo(drawable);
+    }
+
+    @Override
+    public void setStackedBackgroundDrawable(Drawable d) {
+        // This space for rent (do nothing)
+    }
+
+    @Override
+    public void setSplitBackgroundDrawable(Drawable d) {
+        // This space for rent (do nothing)
+    }
+
+    @Override
+    public void setHomeButtonEnabled(boolean enabled) {
+        // If the nav button on a Toolbar is present, it's enabled. No-op.
+    }
+
+    @Override
+    public Context getThemedContext() {
+        return mToolbar.getContext();
+    }
+
+    @Override
+    public boolean isTitleTruncated() {
+        return super.isTitleTruncated();
+    }
+
+    @Override
+    public void setHomeAsUpIndicator(Drawable indicator) {
+        mToolbar.setNavigationIcon(indicator);
+    }
+
+    @Override
+    public void setHomeAsUpIndicator(int resId) {
+        mToolbar.setNavigationIcon(resId);
+    }
+
+    @Override
+    public void setHomeActionContentDescription(CharSequence description) {
+        mToolbar.setNavigationDescription(description);
+    }
+
+    @Override
+    public void setDefaultDisplayHomeAsUpEnabled(boolean enabled) {
+        // Do nothing
+    }
+
+    @Override
+    public void setHomeActionContentDescription(int resId) {
+        mToolbar.setNavigationDescription(resId);
+    }
+
+    @Override
+    public void setShowHideAnimationEnabled(boolean enabled) {
+        // This space for rent; no-op.
+    }
+
+    @Override
+    public void onConfigurationChanged(Configuration config) {
+        super.onConfigurationChanged(config);
+    }
+
+    @Override
+    public ActionMode startActionMode(ActionMode.Callback callback) {
+        return mToolbar.startActionMode(callback);
+    }
+
+    @Override
+    public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
+        throw new UnsupportedOperationException(
+                "Navigation modes are not supported in toolbar action bars");
+    }
+
+    @Override
+    public void setSelectedNavigationItem(int position) {
+        throw new UnsupportedOperationException(
+                "Navigation modes are not supported in toolbar action bars");
+    }
+
+    @Override
+    public int getSelectedNavigationIndex() {
+        return -1;
+    }
+
+    @Override
+    public int getNavigationItemCount() {
+        return 0;
+    }
+
+    @Override
+    public void setTitle(CharSequence title) {
+        mTitle = title;
+        mTitleResId = 0;
+        updateToolbarTitle();
+    }
+
+    @Override
+    public void setTitle(int resId) {
+        mTitleResId = resId;
+        mTitle = null;
+        updateToolbarTitle();
+    }
+
+    @Override
+    public void setSubtitle(CharSequence subtitle) {
+        mSubtitle = subtitle;
+        mSubtitleResId = 0;
+        updateToolbarTitle();
+    }
+
+    @Override
+    public void setSubtitle(int resId) {
+        mSubtitleResId = resId;
+        mSubtitle = null;
+        updateToolbarTitle();
+    }
+
+    private void updateToolbarTitle() {
+        final Context context = mToolbar.getContext();
+        CharSequence title = null;
+        CharSequence subtitle = null;
+        if ((mDisplayOptions & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
+            title = mTitleResId != 0 ? context.getText(mTitleResId) : mTitle;
+            subtitle = mSubtitleResId != 0 ? context.getText(mSubtitleResId) : mSubtitle;
+        }
+        mToolbar.setTitle(title);
+        mToolbar.setSubtitle(subtitle);
+    }
+
+    @Override
+    public void setDisplayOptions(@DisplayOptions int options) {
+        setDisplayOptions(options, 0xffffffff);
+    }
+
+    @Override
+    public void setDisplayOptions(@DisplayOptions int options, @DisplayOptions int mask) {
+        final int oldOptions = mDisplayOptions;
+        mDisplayOptions = (options & mask) | (mDisplayOptions & ~mask);
+        final int optionsChanged = oldOptions ^ mDisplayOptions;
+    }
+
+    @Override
+    public void setDisplayUseLogoEnabled(boolean useLogo) {
+        setDisplayOptions(useLogo ? DISPLAY_USE_LOGO : 0, DISPLAY_USE_LOGO);
+    }
+
+    @Override
+    public void setDisplayShowHomeEnabled(boolean showHome) {
+        setDisplayOptions(showHome ? DISPLAY_SHOW_HOME : 0, DISPLAY_SHOW_HOME);
+    }
+
+    @Override
+    public void setDisplayHomeAsUpEnabled(boolean showHomeAsUp) {
+        setDisplayOptions(showHomeAsUp ? DISPLAY_HOME_AS_UP : 0, DISPLAY_HOME_AS_UP);
+    }
+
+    @Override
+    public void setDisplayShowTitleEnabled(boolean showTitle) {
+        setDisplayOptions(showTitle ? DISPLAY_SHOW_TITLE : 0, DISPLAY_SHOW_TITLE);
+    }
+
+    @Override
+    public void setDisplayShowCustomEnabled(boolean showCustom) {
+        setDisplayOptions(showCustom ? DISPLAY_SHOW_CUSTOM : 0, DISPLAY_SHOW_CUSTOM);
+    }
+
+    @Override
+    public void setBackgroundDrawable(@Nullable Drawable d) {
+        mToolbar.setBackground(d);
+    }
+
+    @Override
+    public View getCustomView() {
+        return mCustomView;
+    }
+
+    @Override
+    public CharSequence getTitle() {
+        return mToolbar.getTitle();
+    }
+
+    @Override
+    public CharSequence getSubtitle() {
+        return mToolbar.getSubtitle();
+    }
+
+    @Override
+    public int getNavigationMode() {
+        return NAVIGATION_MODE_STANDARD;
+    }
+
+    @Override
+    public void setNavigationMode(@NavigationMode int mode) {
+        throw new UnsupportedOperationException(
+                "Navigation modes are not supported in toolbar action bars");
+    }
+
+    @Override
+    public int getDisplayOptions() {
+        return mDisplayOptions;
+    }
+
+    @Override
+    public Tab newTab() {
+        throw new UnsupportedOperationException(
+                "Navigation modes are not supported in toolbar action bars");
+    }
+
+    @Override
+    public void addTab(Tab tab) {
+        throw new UnsupportedOperationException(
+                "Navigation modes are not supported in toolbar action bars");
+    }
+
+    @Override
+    public void addTab(Tab tab, boolean setSelected) {
+        throw new UnsupportedOperationException(
+                "Navigation modes are not supported in toolbar action bars");
+    }
+
+    @Override
+    public void addTab(Tab tab, int position) {
+        throw new UnsupportedOperationException(
+                "Navigation modes are not supported in toolbar action bars");
+    }
+
+    @Override
+    public void addTab(Tab tab, int position, boolean setSelected) {
+        throw new UnsupportedOperationException(
+                "Navigation modes are not supported in toolbar action bars");
+    }
+
+    @Override
+    public void removeTab(Tab tab) {
+        throw new UnsupportedOperationException(
+                "Navigation modes are not supported in toolbar action bars");
+    }
+
+    @Override
+    public void removeTabAt(int position) {
+        throw new UnsupportedOperationException(
+                "Navigation modes are not supported in toolbar action bars");
+    }
+
+    @Override
+    public void removeAllTabs() {
+        throw new UnsupportedOperationException(
+                "Navigation modes are not supported in toolbar action bars");
+    }
+
+    @Override
+    public void selectTab(Tab tab) {
+        throw new UnsupportedOperationException(
+                "Navigation modes are not supported in toolbar action bars");
+    }
+
+    @Override
+    public Tab getSelectedTab() {
+        throw new UnsupportedOperationException(
+                "Navigation modes are not supported in toolbar action bars");
+    }
+
+    @Override
+    public Tab getTabAt(int index) {
+        throw new UnsupportedOperationException(
+                "Navigation modes are not supported in toolbar action bars");
+    }
+
+    @Override
+    public int getTabCount() {
+        return 0;
+    }
+
+    @Override
+    public int getHeight() {
+        return mToolbar.getHeight();
+    }
+
+    @Override
+    public void show() {
+        // TODO: Consider a better transition for this.
+        // Right now use no automatic transition so that the app can supply one if desired.
+        mToolbar.setVisibility(View.VISIBLE);
+    }
+
+    @Override
+    public void hide() {
+        // TODO: Consider a better transition for this.
+        // Right now use no automatic transition so that the app can supply one if desired.
+        mToolbar.setVisibility(View.GONE);
+    }
+
+    @Override
+    public boolean isShowing() {
+        return mToolbar.getVisibility() == View.VISIBLE;
+    }
+
+    public void addOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
+        mMenuVisibilityListeners.add(listener);
+    }
+
+    public void removeOnMenuVisibilityListener(OnMenuVisibilityListener listener) {
+        mMenuVisibilityListeners.remove(listener);
+    }
+
+    public void dispatchMenuVisibilityChanged(boolean isVisible) {
+        if (isVisible == mLastMenuVisibility) {
+            return;
+        }
+        mLastMenuVisibility = isVisible;
+
+        final int count = mMenuVisibilityListeners.size();
+        for (int i = 0; i < count; i++) {
+            mMenuVisibilityListeners.get(i).onMenuVisibilityChanged(isVisible);
+        }
+    }
+
+    @Override
+    public void captureSharedElements(Map<String, View> sharedElements) {
+        mToolbar.findSharedElements(sharedElements);
+    }
+}
diff --git a/core/java/com/android/internal/app/ActionBarImpl.java b/core/java/com/android/internal/app/WindowDecorActionBar.java
similarity index 98%
rename from core/java/com/android/internal/app/ActionBarImpl.java
rename to core/java/com/android/internal/app/WindowDecorActionBar.java
index 80e1caa..c6afae0 100644
--- a/core/java/com/android/internal/app/ActionBarImpl.java
+++ b/core/java/com/android/internal/app/WindowDecorActionBar.java
@@ -60,14 +60,14 @@
 import java.util.Map;
 
 /**
- * ActionBarImpl is the ActionBar implementation used
- * by devices of all screen sizes. If it detects a compatible decor,
- * it will split contextual modes across both the ActionBarView at
- * the top of the screen and a horizontal LinearLayout at the bottom
- * which is normally hidden.
+ * WindowDecorActionBar is the ActionBar implementation used
+ * by devices of all screen sizes as part of the window decor layout.
+ * If it detects a compatible decor, it will 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 ActionBarImpl extends ActionBar {
-    private static final String TAG = "ActionBarImpl";
+public class WindowDecorActionBar extends ActionBar {
+    private static final String TAG = "WindowDecorActionBar";
 
     private Context mContext;
     private Context mThemedContext;
@@ -105,9 +105,6 @@
     private int mContextDisplayMode;
     private boolean mHasEmbeddedTabs;
 
-    final Handler mHandler = new Handler();
-    Runnable mTabSelector;
-
     private int mCurWindowVisibility = View.VISIBLE;
 
     private boolean mContentAnimations = true;
@@ -157,7 +154,7 @@
         }
     };
 
-    public ActionBarImpl(Activity activity) {
+    public WindowDecorActionBar(Activity activity) {
         mActivity = activity;
         Window window = activity.getWindow();
         View decor = window.getDecorView();
@@ -168,7 +165,7 @@
         }
     }
 
-    public ActionBarImpl(Dialog dialog) {
+    public WindowDecorActionBar(Dialog dialog) {
         mDialog = dialog;
         init(dialog.getWindow().getDecorView());
     }
diff --git a/core/java/com/android/internal/view/menu/ActionMenuItemView.java b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
index 3cceebe..891baea 100644
--- a/core/java/com/android/internal/view/menu/ActionMenuItemView.java
+++ b/core/java/com/android/internal/view/menu/ActionMenuItemView.java
@@ -282,11 +282,6 @@
 
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
-        if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
-            // Fill all available height.
-            heightMeasureSpec = MeasureSpec.makeMeasureSpec(
-                    MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.EXACTLY);
-        }
         final boolean textVisible = hasText();
         if (textVisible && mSavedPaddingLeft >= 0) {
             super.setPadding(mSavedPaddingLeft, getPaddingTop(),
diff --git a/core/java/com/android/internal/widget/ActionBarContainer.java b/core/java/com/android/internal/widget/ActionBarContainer.java
index c2d22dd..ed07514 100644
--- a/core/java/com/android/internal/widget/ActionBarContainer.java
+++ b/core/java/com/android/internal/widget/ActionBarContainer.java
@@ -43,6 +43,7 @@
     private Drawable mSplitBackground;
     private boolean mIsSplit;
     private boolean mIsStacked;
+    private int mHeight;
 
     public ActionBarContainer(Context context) {
         this(context, null);
@@ -59,6 +60,7 @@
         mBackground = a.getDrawable(com.android.internal.R.styleable.ActionBar_background);
         mStackedBackground = a.getDrawable(
                 com.android.internal.R.styleable.ActionBar_backgroundStacked);
+        mHeight = a.getDimensionPixelSize(com.android.internal.R.styleable.ActionBar_height, -1);
 
         if (getId() == com.android.internal.R.id.split_action_bar) {
             mIsSplit = true;
@@ -251,6 +253,11 @@
 
     @Override
     public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+        if (mActionBarView == null &&
+                MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST && mHeight >= 0) {
+            heightMeasureSpec = MeasureSpec.makeMeasureSpec(
+                    Math.min(mHeight, MeasureSpec.getSize(heightMeasureSpec)), MeasureSpec.AT_MOST);
+        }
         super.onMeasure(widthMeasureSpec, heightMeasureSpec);
 
         if (mActionBarView == null) return;
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index adb9bf8..c9dff1a 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -21,7 +21,7 @@
 import android.os.Build;
 import android.view.ViewGroup;
 import android.view.WindowInsets;
-import com.android.internal.app.ActionBarImpl;
+import com.android.internal.app.WindowDecorActionBar;
 
 import android.content.Context;
 import android.content.res.TypedArray;
@@ -38,7 +38,7 @@
     private static final String TAG = "ActionBarOverlayLayout";
 
     private int mActionBarHeight;
-    private ActionBarImpl mActionBar;
+    private WindowDecorActionBar mActionBar;
     private int mWindowVisibility = View.VISIBLE;
 
     // The main UI elements that we handle the layout of.
@@ -88,7 +88,7 @@
                 Build.VERSION_CODES.KITKAT;
     }
 
-    public void setActionBar(ActionBarImpl impl) {
+    public void setActionBar(WindowDecorActionBar impl) {
         mActionBar = impl;
         if (getWindowToken() != null) {
             // This is being initialized after being added to a window;
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 1273c4d..60631b9 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -430,7 +430,7 @@
             mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);
             // Span the whole width
             layoutParams.width = LayoutParams.MATCH_PARENT;
-            layoutParams.height = mContentHeight;
+            layoutParams.height = LayoutParams.WRAP_CONTENT;
             configPresenters(builder);
             menuView = (ActionMenuView) mActionMenuPresenter.getMenuView(this);
             if (mSplitView != null) {
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index aa5005f..00b61a5 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -650,6 +650,8 @@
         <!-- Default ActivityChooserView style. -->
         <attr name="activityChooserViewStyle" format="reference" />
 
+        <attr name="toolbarStyle" format="reference" />
+
         <!-- Fast scroller styles -->
         <eat-comment />
 
@@ -6235,10 +6237,6 @@
         <attr name="inputType" />
     </declare-styleable>
 
-    <declare-styleable name="ActionBar_LayoutParams">
-        <attr name="layout_gravity" />
-    </declare-styleable>
-
     <declare-styleable name="Switch">
         <!-- Drawable to use as the "thumb" that switches back and forth. -->
         <attr name="thumb" />
@@ -6447,4 +6445,21 @@
         <attr name="textView" format="reference" />
     </declare-styleable>
 
+    <declare-styleable name="Toolbar">
+        <attr name="titleTextAppearance" format="reference" />
+        <attr name="subtitleTextAppearance" format="reference" />
+        <attr name="title" />
+        <attr name="subtitle" />
+        <attr name="gravity" />
+        <attr name="titleMargins" format="dimension" />
+        <attr name="titleMarginStart" format="dimension" />
+        <attr name="titleMarginEnd" format="dimension" />
+        <attr name="titleMarginTop" format="dimension" />
+        <attr name="titleMarginBottom" format="dimension" />
+    </declare-styleable>
+
+    <declare-styleable name="Toolbar_LayoutParams">
+        <attr name="layout_gravity" />
+    </declare-styleable>
+
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 667adde..76a3bd7 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2143,6 +2143,8 @@
   <public type="attr" name="colorButtonNormalColored" />
   <public type="attr" name="colorButtonPressedColored" />
   <public type="attr" name="persistable" />
+  <public type="attr" name="titleTextAppearance" />
+  <public type="attr" name="subtitleTextAppearance" />
 
   <public-padding type="dimen" name="l_resource_pad" end="0x01050010" />
 
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index be875ff..fc0fccc 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1208,6 +1208,13 @@
         <item name="android:subtitleTextStyle">@android:style/TextAppearance.Widget.ActionMode.Subtitle</item>
     </style>
 
+    <style name="Widget.Toolbar">
+        <item name="android:titleTextAppearance">@android:style/TextAppearance.Widget.Toolbar.Title</item>
+        <item name="android:subtitleTextAppearance">@android:style/TextAppearance.Widget.Toolbar.Subtitle</item>
+        <item name="android:minHeight">?android:attr/actionBarSize</item>
+        <item name="android:titleMargins">4dp</item>
+    </style>
+
     <style name="TextAppearance.Widget.ActionBar.Title"
            parent="@android:style/TextAppearance.Medium">
     </style>
@@ -1225,6 +1232,14 @@
         <item name="android:textColor">?android:attr/textColorSecondary</item>
     </style>
 
+    <style name="TextAppearance.Widget.Toolbar.Title"
+           parent="@android:style/TextAppearance.Widget.ActionBar.Title">
+    </style>
+
+    <style name="TextAppearance.Widget.Toolbar.Subtitle"
+           parent="@android:style/TextAppearance.Widget.ActionBar.Subtitle">
+    </style>
+
     <style name="Widget.ActionButton">
         <item name="android:background">?android:attr/actionBarItemBackground</item>
         <item name="android:paddingStart">12dip</item>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 557dce24..57075ee 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1829,4 +1829,8 @@
   <java-symbol type="color" name="timepicker_default_ampm_selected_background_color_holo_light" />
   <java-symbol type="array" name="config_clockTickVibePattern" />
 
+  <java-symbol type="attr" name="toolbarStyle" />
+  <java-symbol type="attr" name="titleTextAppearance" />
+  <java-symbol type="attr" name="subtitleTextAppearance" />
+
 </resources>
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index 3c4e848..7aea814 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -352,6 +352,8 @@
         <item name="actionBarDivider">?android:attr/dividerVertical</item>
         <item name="actionBarItemBackground">?android:attr/selectableItemBackground</item>
 
+        <item name="toolbarStyle">@android:style/Widget.Toolbar</item>
+
         <item name="dividerVertical">@drawable/divider_vertical_dark</item>
         <item name="dividerHorizontal">@drawable/divider_vertical_dark</item>
         <item name="buttonBarStyle">@android:style/ButtonBar</item>