Merge "Camera2: Update spec for thumbnail cropping behavior" into lmp-preview-dev
diff --git a/api/current.txt b/api/current.txt
index dddd6ae..2b6189a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -27426,306 +27426,6 @@
 
 }
 
-package android.telecomm {
-
-  public final class CallAudioState implements android.os.Parcelable {
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-    field public static int ROUTE_ALL;
-    field public static int ROUTE_BLUETOOTH;
-    field public static int ROUTE_EARPIECE;
-    field public static int ROUTE_SPEAKER;
-    field public static int ROUTE_WIRED_HEADSET;
-    field public static int ROUTE_WIRED_OR_EARPIECE;
-    field public final boolean isMuted;
-    field public final int route;
-    field public final int supportedRouteMask;
-  }
-
-  public class CallCapabilities {
-    ctor public CallCapabilities();
-    field public static final int ADD_CALL = 16; // 0x10
-    field public static final int ALL = 511; // 0x1ff
-    field public static final int CONNECTION_HANDOFF = 256; // 0x100
-    field public static final int GENERIC_CONFERENCE = 128; // 0x80
-    field public static final int HOLD = 1; // 0x1
-    field public static final int MERGE_CALLS = 4; // 0x4
-    field public static final int MUTE = 64; // 0x40
-    field public static final int RESPOND_VIA_TEXT = 32; // 0x20
-    field public static final int SUPPORT_HOLD = 2; // 0x2
-    field public static final int SWAP_CALLS = 8; // 0x8
-  }
-
-  public final class CallInfo implements android.os.Parcelable {
-    ctor public CallInfo(java.lang.String, android.telecomm.CallState, android.net.Uri);
-    method public int describeContents();
-    method public android.telecomm.CallServiceDescriptor getCurrentCallServiceDescriptor();
-    method public android.os.Bundle getExtras();
-    method public android.telecomm.GatewayInfo getGatewayInfo();
-    method public android.net.Uri getHandle();
-    method public java.lang.String getId();
-    method public android.net.Uri getOriginalHandle();
-    method public android.telecomm.CallState getState();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-  }
-
-  public final class CallNumberPresentation extends java.lang.Enum {
-    method public static android.telecomm.CallNumberPresentation valueOf(java.lang.String);
-    method public static final android.telecomm.CallNumberPresentation[] values();
-    enum_constant public static final android.telecomm.CallNumberPresentation ALLOWED;
-    enum_constant public static final android.telecomm.CallNumberPresentation PAYPHONE;
-    enum_constant public static final android.telecomm.CallNumberPresentation RESTRICTED;
-    enum_constant public static final android.telecomm.CallNumberPresentation UNKNOWN;
-  }
-
-  public abstract class CallService extends android.app.Service {
-    ctor public CallService();
-    method public abstract void abort(java.lang.String);
-    method public abstract void answer(java.lang.String);
-    method public abstract void call(android.telecomm.CallInfo);
-    method public abstract void disconnect(java.lang.String);
-    method protected final android.telecomm.CallServiceAdapter getAdapter();
-    method public final android.os.IBinder getBinder();
-    method public abstract void hold(java.lang.String);
-    method public abstract void isCompatibleWith(android.telecomm.CallInfo);
-    method protected void onAdapterAttached(android.telecomm.CallServiceAdapter);
-    method public abstract void onAudioStateChanged(java.lang.String, android.telecomm.CallAudioState);
-    method public final android.os.IBinder onBind(android.content.Intent);
-    method public abstract void playDtmfTone(java.lang.String, char);
-    method public abstract void reject(java.lang.String);
-    method public abstract void setIncomingCallId(java.lang.String, android.os.Bundle);
-    method public abstract void stopDtmfTone(java.lang.String);
-    method public abstract void unhold(java.lang.String);
-  }
-
-  public final class CallServiceAdapter {
-    method public void handleFailedOutgoingCall(java.lang.String, java.lang.String);
-    method public void handleSuccessfulOutgoingCall(java.lang.String);
-    method public void notifyIncomingCall(android.telecomm.CallInfo);
-    method public void setActive(java.lang.String);
-    method public void setDialing(java.lang.String);
-    method public void setDisconnected(java.lang.String, int, java.lang.String);
-    method public void setIsCompatibleWith(java.lang.String, boolean);
-    method public void setOnHold(java.lang.String);
-    method public void setRinging(java.lang.String);
-  }
-
-  public final class CallServiceDescriptor implements android.os.Parcelable {
-    method public int describeContents();
-    method public java.lang.String getCallServiceId();
-    method public int getNetworkType();
-    method public android.content.ComponentName getServiceComponent();
-    method public static android.telecomm.CallServiceDescriptor.Builder newBuilder(android.content.Context);
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-    field public static final int FLAG_MOBILE = 4; // 0x4
-    field public static final int FLAG_PSTN = 2; // 0x2
-    field public static final int FLAG_WIFI = 1; // 0x1
-  }
-
-  public static class CallServiceDescriptor.Builder {
-    method public android.telecomm.CallServiceDescriptor build();
-    method public android.telecomm.CallServiceDescriptor.Builder setCallService(java.lang.Class<? extends android.telecomm.CallService>);
-    method public android.telecomm.CallServiceDescriptor.Builder setNetworkType(int);
-  }
-
-  public final class CallServiceLookupResponse {
-    method public void setCallServiceDescriptors(java.util.List<android.telecomm.CallServiceDescriptor>);
-  }
-
-  public abstract class CallServiceProvider extends android.app.Service {
-    ctor protected CallServiceProvider();
-    method public abstract void lookupCallServices(android.telecomm.CallServiceLookupResponse);
-    method public android.os.IBinder onBind(android.content.Intent);
-  }
-
-  public abstract class CallServiceSelector extends android.app.Service {
-    ctor protected CallServiceSelector();
-    method protected final void cancelOutgoingCall(android.telecomm.CallInfo);
-    method protected final android.telecomm.CallServiceSelectorAdapter getAdapter();
-    method protected final java.util.Collection<android.telecomm.CallInfo> getCalls();
-    method protected void onAdapterAttached(android.telecomm.CallServiceSelectorAdapter);
-    method public final android.os.IBinder onBind(android.content.Intent);
-    method protected abstract void select(android.telecomm.CallInfo, java.util.List<android.telecomm.CallServiceDescriptor>);
-  }
-
-  public final class CallServiceSelectorAdapter {
-    method public void cancelOutgoingCall(java.lang.String);
-    method public void setHandoffInfo(java.lang.String, android.net.Uri, android.os.Bundle);
-    method public void setSelectedCallServices(java.lang.String, java.util.List<android.telecomm.CallServiceDescriptor>);
-  }
-
-  public final class CallState extends java.lang.Enum {
-    method public static android.telecomm.CallState valueOf(java.lang.String);
-    method public static final android.telecomm.CallState[] values();
-    enum_constant public static final android.telecomm.CallState ACTIVE;
-    enum_constant public static final android.telecomm.CallState DIALING;
-    enum_constant public static final android.telecomm.CallState DISCONNECTED;
-    enum_constant public static final android.telecomm.CallState NEW;
-    enum_constant public static final android.telecomm.CallState ON_HOLD;
-    enum_constant public static final android.telecomm.CallState POST_DIAL;
-    enum_constant public static final android.telecomm.CallState POST_DIAL_WAIT;
-    enum_constant public static final android.telecomm.CallState RINGING;
-  }
-
-  public abstract class Connection {
-    ctor protected Connection();
-    method public final android.telecomm.CallAudioState getCallAudioState();
-    method public final android.net.Uri getHandle();
-    method protected void onAbort();
-    method protected void onAnswer();
-    method protected void onDisconnect();
-    method protected void onHold();
-    method protected void onPlayDtmfTone(char);
-    method protected void onReject();
-    method protected void onSetAudioState(android.telecomm.CallAudioState);
-    method protected void onSetSignal(android.os.Bundle);
-    method protected void onStopDtmfTone();
-    method protected void onUnhold();
-    method protected void setActive();
-    method public void setAudioState(android.telecomm.CallAudioState);
-    method protected void setDialing();
-    method protected void setDisconnected(int, java.lang.String);
-    method protected void setHandle(android.net.Uri);
-    method protected void setOnHold();
-    method protected void setRinging();
-    method public static java.lang.String stateToString(int);
-  }
-
-  public static abstract interface Connection.Listener {
-    method public abstract void onAudioStateChanged(android.telecomm.Connection, android.telecomm.CallAudioState);
-    method public abstract void onDestroyed(android.telecomm.Connection);
-    method public abstract void onDisconnected(android.telecomm.Connection, int, java.lang.String);
-    method public abstract void onHandleChanged(android.telecomm.Connection, android.net.Uri);
-    method public abstract void onSignalChanged(android.telecomm.Connection, android.os.Bundle);
-    method public abstract void onStateChanged(android.telecomm.Connection, int);
-  }
-
-  public static class Connection.ListenerBase implements android.telecomm.Connection.Listener {
-    ctor public Connection.ListenerBase();
-    method public void onAudioStateChanged(android.telecomm.Connection, android.telecomm.CallAudioState);
-    method public void onDestroyed(android.telecomm.Connection);
-    method public void onDisconnected(android.telecomm.Connection, int, java.lang.String);
-    method public void onHandleChanged(android.telecomm.Connection, android.net.Uri);
-    method public void onSignalChanged(android.telecomm.Connection, android.os.Bundle);
-    method public void onStateChanged(android.telecomm.Connection, int);
-  }
-
-  public final class Connection.State {
-    field public static final int ACTIVE = 3; // 0x3
-    field public static final int DIALING = 2; // 0x2
-    field public static final int DISCONNECTED = 5; // 0x5
-    field public static final int HOLDING = 4; // 0x4
-    field public static final int NEW = 0; // 0x0
-    field public static final int RINGING = 1; // 0x1
-  }
-
-  public final class ConnectionRequest {
-    ctor public ConnectionRequest(android.net.Uri, android.os.Bundle);
-    method public android.os.Bundle getExtras();
-    method public android.net.Uri getHandle();
-  }
-
-  public abstract class ConnectionService extends android.telecomm.CallService {
-    ctor public ConnectionService();
-    method public final void abort(java.lang.String);
-    method public final void answer(java.lang.String);
-    method public final void call(android.telecomm.CallInfo);
-    method public final void disconnect(java.lang.String);
-    method public final void hold(java.lang.String);
-    method public final void isCompatibleWith(android.telecomm.CallInfo);
-    method public final void onAudioStateChanged(java.lang.String, android.telecomm.CallAudioState);
-    method public void onCreateConnections(android.telecomm.ConnectionRequest, android.telecomm.Response<android.telecomm.ConnectionRequest, android.telecomm.Connection>);
-    method public void onCreateIncomingConnection(android.telecomm.ConnectionRequest, android.telecomm.Response<android.telecomm.ConnectionRequest, android.telecomm.Connection>);
-    method public void onFindSubscriptions(android.net.Uri, android.telecomm.Response<android.net.Uri, android.telecomm.Subscription>);
-    method public final void playDtmfTone(java.lang.String, char);
-    method public final void reject(java.lang.String);
-    method public final void setIncomingCallId(java.lang.String, android.os.Bundle);
-    method public final void stopDtmfTone(java.lang.String);
-    method public final void unhold(java.lang.String);
-  }
-
-  public class GatewayInfo implements android.os.Parcelable {
-    method public int describeContents();
-    method public android.net.Uri getGatewayHandle();
-    method public java.lang.String getGatewayProviderPackageName();
-    method public android.net.Uri getOriginalHandle();
-    method public boolean isEmpty();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-  }
-
-  public final class InCallAdapter {
-    method public void answerCall(java.lang.String);
-    method public void disconnectCall(java.lang.String);
-    method public void handoffCall(java.lang.String);
-    method public void holdCall(java.lang.String);
-    method public void mute(boolean);
-    method public void playDtmfTone(java.lang.String, char);
-    method public void postDialContinue(java.lang.String);
-    method public void rejectCall(java.lang.String);
-    method public void setAudioRoute(int);
-    method public void stopDtmfTone(java.lang.String);
-    method public void unholdCall(java.lang.String);
-  }
-
-  public final class InCallCall implements android.os.Parcelable {
-    method public int describeContents();
-    method public int getCapabilities();
-    method public long getConnectTimeMillis();
-    method public android.telecomm.CallServiceDescriptor getCurrentCallServiceDescriptor();
-    method public int getDisconnectCause();
-    method public android.telecomm.GatewayInfo getGatewayInfo();
-    method public android.net.Uri getHandle();
-    method public android.telecomm.CallServiceDescriptor getHandoffCallServiceDescriptor();
-    method public java.lang.String getId();
-    method public android.telecomm.CallState getState();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-  }
-
-  public abstract class InCallService extends android.app.Service {
-    ctor protected InCallService();
-    method protected abstract void addCall(android.telecomm.InCallCall);
-    method protected final android.telecomm.InCallAdapter getAdapter();
-    method protected void onAdapterAttached(android.telecomm.InCallAdapter);
-    method protected abstract void onAudioStateChanged(android.telecomm.CallAudioState);
-    method public final android.os.IBinder onBind(android.content.Intent);
-    method protected abstract void setPostDial(java.lang.String, java.lang.String);
-    method protected abstract void setPostDialWait(java.lang.String, java.lang.String);
-    method protected abstract void updateCall(android.telecomm.InCallCall);
-  }
-
-  public abstract interface Response {
-    method public abstract void onError(IN, java.lang.String);
-    method public abstract void onResult(IN, OUT...);
-  }
-
-  public class Subscription implements android.os.Parcelable {
-    ctor public Subscription();
-    method public int describeContents();
-    method public void writeToParcel(android.os.Parcel, int);
-    field public static final android.os.Parcelable.Creator CREATOR;
-  }
-
-  public final class TelecommConstants {
-    ctor public TelecommConstants();
-    field public static final java.lang.String ACTION_CALL_SERVICE;
-    field public static final java.lang.String ACTION_CALL_SERVICE_PROVIDER;
-    field public static final java.lang.String ACTION_CALL_SERVICE_SELECTOR;
-    field public static final java.lang.String ACTION_INCOMING_CALL = "android.intent.action.INCOMING_CALL";
-    field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
-    field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
-    field public static final java.lang.String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecomm.extra.CALL_DISCONNECT_CAUSE";
-    field public static final java.lang.String EXTRA_CALL_DISCONNECT_MESSAGE = "android.telecomm.extra.CALL_DISCONNECT_MESSAGE";
-    field public static final java.lang.String EXTRA_CALL_SERVICE_DESCRIPTOR = "android.intent.extra.CALL_SERVICE_DESCRIPTOR";
-    field public static final java.lang.String EXTRA_INCOMING_CALL_EXTRAS = "android.intent.extra.INCOMING_CALL_EXTRAS";
-  }
-
-}
-
 package android.telephony {
 
   public final class CellIdentityCdma implements android.os.Parcelable {
@@ -35848,10 +35548,14 @@
   public class ActionMenuView extends android.widget.LinearLayout {
     ctor public ActionMenuView(android.content.Context);
     ctor public ActionMenuView(android.content.Context, android.util.AttributeSet);
+    method public void dismissPopupMenus();
     method public android.view.Menu getMenu();
+    method public boolean hideOverflowMenu();
+    method public boolean isOverflowMenuShowing();
     method public void onConfigurationChanged(android.content.res.Configuration);
     method public void onDetachedFromWindow();
     method public void setOnMenuItemClickListener(android.widget.ActionMenuView.OnMenuItemClickListener);
+    method public boolean showOverflowMenu();
   }
 
   public static class ActionMenuView.LayoutParams extends android.widget.LinearLayout.LayoutParams {
@@ -38029,6 +37733,8 @@
     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 void collapseActionView();
+    method public void dismissPopupMenus();
     method public int getContentInsetEnd();
     method public int getContentInsetLeft();
     method public int getContentInsetRight();
@@ -38039,7 +37745,10 @@
     method public android.graphics.drawable.Drawable getNavigationIcon();
     method public java.lang.CharSequence getSubtitle();
     method public java.lang.CharSequence getTitle();
+    method public boolean hasExpandedActionView();
+    method public boolean hideOverflowMenu();
     method public void inflateMenu(int);
+    method public boolean isOverflowMenuShowing();
     method protected void onLayout(boolean, int, int, int, int);
     method public void setContentInsetsAbsolute(int, int);
     method public void setContentInsetsRelative(int, int);
@@ -38047,6 +37756,8 @@
     method public void setLogo(android.graphics.drawable.Drawable);
     method public void setLogoDescription(int);
     method public void setLogoDescription(java.lang.CharSequence);
+    method public void setNavigationContentDescription(java.lang.CharSequence);
+    method public void setNavigationContentDescription(int);
     method public void setNavigationDescription(int);
     method public void setNavigationDescription(java.lang.CharSequence);
     method public void setNavigationIcon(int);
@@ -38057,17 +37768,18 @@
     method public void setSubtitle(java.lang.CharSequence);
     method public void setTitle(int);
     method public void setTitle(java.lang.CharSequence);
+    method public boolean showOverflowMenu();
   }
 
-  public static class Toolbar.LayoutParams extends android.view.ViewGroup.MarginLayoutParams {
+  public static class Toolbar.LayoutParams extends android.app.ActionBar.LayoutParams {
     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.app.ActionBar.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 {
diff --git a/core/java/android/app/ActionBar.java b/core/java/android/app/ActionBar.java
index 3c3df01..f05f4c7 100644
--- a/core/java/android/app/ActionBar.java
+++ b/core/java/android/app/ActionBar.java
@@ -1291,6 +1291,7 @@
 
         public LayoutParams(int width, int height) {
             super(width, height);
+            this.gravity = Gravity.CENTER_VERTICAL | Gravity.START;
         }
 
         public LayoutParams(int width, int height, int gravity) {
@@ -1305,6 +1306,7 @@
 
         public LayoutParams(LayoutParams source) {
             super(source);
+            this.gravity = source.gravity;
         }
 
         public LayoutParams(ViewGroup.LayoutParams source) {
diff --git a/core/java/android/hardware/camera2/params/ColorSpaceTransform.java b/core/java/android/hardware/camera2/params/ColorSpaceTransform.java
index 503af26..b4289db2 100644
--- a/core/java/android/hardware/camera2/params/ColorSpaceTransform.java
+++ b/core/java/android/hardware/camera2/params/ColorSpaceTransform.java
@@ -139,8 +139,8 @@
             throw new IllegalArgumentException("row out of range");
         }
 
-        int numerator = mElements[row * ROWS * RATIONAL_SIZE + column + OFFSET_NUMERATOR];
-        int denominator = mElements[row * ROWS * RATIONAL_SIZE + column + OFFSET_DENOMINATOR];
+        int numerator = mElements[(row * COLUMNS + column) * RATIONAL_SIZE + OFFSET_NUMERATOR];
+        int denominator = mElements[(row * COLUMNS + column) * RATIONAL_SIZE + OFFSET_DENOMINATOR];
 
         return new Rational(numerator, denominator);
     }
diff --git a/core/java/android/net/NetworkAgent.java b/core/java/android/net/NetworkAgent.java
index c2b06a2..1c18ba5 100644
--- a/core/java/android/net/NetworkAgent.java
+++ b/core/java/android/net/NetworkAgent.java
@@ -257,31 +257,43 @@
     }
 
     /**
-     * called to go through our list of requests and see if we're
-     * good enough to try connecting.
+     * Called to go through our list of requests and see if we're
+     * good enough to try connecting, or if we have gotten worse and
+     * need to disconnect.
      *
-     * Only does connects - we disconnect when requested via
+     * Once we are registered, does nothing: we disconnect when requested via
      * CMD_CHANNEL_DISCONNECTED, generated by either a loss of connection
      * between modules (bearer or ConnectivityService dies) or more commonly
      * when the NetworkInfo reports to ConnectivityService it is disconnected.
      */
     private void evalScores() {
-        if (mConnectionRequested) {
-            if (VDBG) log("evalScores - already trying - size=" + mNetworkRequests.size());
-            // already trying
-            return;
-        }
-        if (VDBG) log("evalScores!");
-        for (int i=0; i < mNetworkRequests.size(); i++) {
-            int score = mNetworkRequests.valueAt(i).score;
-            if (VDBG) log(" checking request Min " + score + " vs my score " + mNetworkScore);
-            if (score < mNetworkScore) {
-                // have a request that has a lower scored network servicing it
-                // (or no network) than we could provide, so lets connect!
-                mConnectionRequested = true;
-                connect();
+        synchronized(mLockObj) {
+            if (mRegistered) {
+                if (VDBG) log("evalScores - already connected - size=" + mNetworkRequests.size());
+                // already trying
                 return;
             }
+            if (VDBG) log("evalScores!");
+            for (int i=0; i < mNetworkRequests.size(); i++) {
+                int score = mNetworkRequests.valueAt(i).score;
+                if (VDBG) log(" checking request Min " + score + " vs my score " + mNetworkScore);
+                if (score < mNetworkScore) {
+                    // have a request that has a lower scored network servicing it
+                    // (or no network) than we could provide, so let's connect!
+                    mConnectionRequested = true;
+                    connect();
+                    return;
+                }
+            }
+            // Our score is not high enough to satisfy any current request.
+            // This can happen if our score goes down after a connection is
+            // requested but before we actually connect. In this case, disconnect
+            // rather than continue trying - there's no point connecting if we know
+            // we'll just be torn down as soon as we do.
+            if (mConnectionRequested) {
+                mConnectionRequested = false;
+                disconnect();
+            }
         }
     }
 
diff --git a/core/java/android/widget/ActionMenuPresenter.java b/core/java/android/widget/ActionMenuPresenter.java
index 51759c5..1fddf3e 100644
--- a/core/java/android/widget/ActionMenuPresenter.java
+++ b/core/java/android/widget/ActionMenuPresenter.java
@@ -544,6 +544,7 @@
 
     public void setMenuView(ActionMenuView menuView) {
         mMenuView = menuView;
+        menuView.initialize(mMenu);
     }
 
     private static class SavedState implements Parcelable {
diff --git a/core/java/android/widget/ActionMenuView.java b/core/java/android/widget/ActionMenuView.java
index 3975edf..a9a5eae 100644
--- a/core/java/android/widget/ActionMenuView.java
+++ b/core/java/android/widget/ActionMenuView.java
@@ -69,6 +69,7 @@
     /** @hide */
     public void setPresenter(ActionMenuPresenter presenter) {
         mPresenter = presenter;
+        mPresenter.setMenuView(this);
     }
 
     @Override
@@ -488,7 +489,7 @@
     @Override
     public void onDetachedFromWindow() {
         super.onDetachedFromWindow();
-        mPresenter.dismissPopupMenus();
+        dismissPopupMenus();
     }
 
     /** @hide */
@@ -578,6 +579,56 @@
     }
 
     /**
+     * Returns the current menu or null if one has not yet been configured.
+     * @hide Internal use only for action bar integration
+     */
+    public MenuBuilder peekMenu() {
+        return mMenu;
+    }
+
+    /**
+     * Show the overflow items from the associated menu.
+     *
+     * @return true if the menu was able to be shown, false otherwise
+     */
+    public boolean showOverflowMenu() {
+        return mPresenter != null && mPresenter.showOverflowMenu();
+    }
+
+    /**
+     * Hide the overflow items from the associated menu.
+     *
+     * @return true if the menu was able to be hidden, false otherwise
+     */
+    public boolean hideOverflowMenu() {
+        return mPresenter != null && mPresenter.hideOverflowMenu();
+    }
+
+    /**
+     * Check whether the overflow menu is currently showing. This may not reflect
+     * a pending show operation in progress.
+     *
+     * @return true if the overflow menu is currently showing
+     */
+    public boolean isOverflowMenuShowing() {
+        return mPresenter != null && mPresenter.isOverflowMenuShowing();
+    }
+
+    /** @hide */
+    public boolean isOverflowMenuShowPending() {
+        return mPresenter != null && mPresenter.isOverflowMenuShowPending();
+    }
+
+    /**
+     * Dismiss any popups associated with this menu view.
+     */
+    public void dismissPopupMenus() {
+        if (mPresenter != null) {
+            mPresenter.dismissPopupMenus();
+        }
+    }
+
+    /**
      * @hide Private LinearLayout (superclass) API. Un-hide if LinearLayout API is made public.
      */
     @Override
diff --git a/core/java/android/widget/Toolbar.java b/core/java/android/widget/Toolbar.java
index f903346..8c67bb7 100644
--- a/core/java/android/widget/Toolbar.java
+++ b/core/java/android/widget/Toolbar.java
@@ -18,13 +18,17 @@
 package android.widget;
 
 import android.annotation.NonNull;
+import android.app.ActionBar;
 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.Layout;
 import android.text.TextUtils;
 import android.util.AttributeSet;
+import android.util.Log;
+import android.view.CollapsibleActionView;
 import android.view.Gravity;
 import android.view.Menu;
 import android.view.MenuInflater;
@@ -32,7 +36,15 @@
 import android.view.View;
 import android.view.ViewDebug;
 import android.view.ViewGroup;
+import android.view.Window;
 import com.android.internal.R;
+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;
+import com.android.internal.view.menu.SubMenuBuilder;
+import com.android.internal.widget.DecorToolbar;
+import com.android.internal.widget.ToolbarWidgetWrapper;
 
 import java.util.ArrayList;
 import java.util.List;
@@ -80,14 +92,25 @@
  * layout is discouraged on API 21 devices and newer.</p>
  */
 public class Toolbar extends ViewGroup {
+    private static final String TAG = "Toolbar";
+
     private ActionMenuView mMenuView;
     private TextView mTitleTextView;
     private TextView mSubtitleTextView;
     private ImageButton mNavButtonView;
     private ImageView mLogoView;
 
+    private Drawable mCollapseIcon;
+    private ImageButton mCollapseButtonView;
+    View mExpandedActionView;
+
     private int mTitleTextAppearance;
     private int mSubtitleTextAppearance;
+    private int mNavButtonStyle;
+
+    private int mButtonGravity;
+
+    private int mMaxButtonHeight;
 
     private int mTitleMarginStart;
     private int mTitleMarginEnd;
@@ -117,6 +140,10 @@
                 }
             };
 
+    private ToolbarWidgetWrapper mWrapper;
+    private ActionMenuPresenter mOuterActionMenuPresenter;
+    private ExpandedActionViewMenuPresenter mExpandedMenuPresenter;
+
     public Toolbar(Context context) {
         this(context, null);
     }
@@ -137,7 +164,9 @@
 
         mTitleTextAppearance = a.getResourceId(R.styleable.Toolbar_titleTextAppearance, 0);
         mSubtitleTextAppearance = a.getResourceId(R.styleable.Toolbar_subtitleTextAppearance, 0);
+        mNavButtonStyle = a.getResourceId(R.styleable.Toolbar_navigationButtonStyle, 0);
         mGravity = a.getInteger(R.styleable.Toolbar_gravity, mGravity);
+        mButtonGravity = a.getInteger(R.styleable.Toolbar_buttonGravity, Gravity.TOP);
         mTitleMarginStart = mTitleMarginEnd = mTitleMarginTop = mTitleMarginBottom =
                 a.getDimensionPixelOffset(R.styleable.Toolbar_titleMargins, 0);
 
@@ -162,6 +191,8 @@
             mTitleMarginBottom = marginBottom;
         }
 
+        mMaxButtonHeight = a.getDimensionPixelSize(R.styleable.Toolbar_maxButtonHeight, -1);
+
         final int contentInsetStart =
                 a.getDimensionPixelOffset(R.styleable.Toolbar_contentInsetStart,
                         RtlSpacingHelper.UNDEFINED);
@@ -180,6 +211,8 @@
             mContentInsets.setRelative(contentInsetStart, contentInsetEnd);
         }
 
+        mCollapseIcon = a.getDrawable(R.styleable.Toolbar_collapseIcon);
+
         final CharSequence title = a.getText(R.styleable.Toolbar_title);
         if (!TextUtils.isEmpty(title)) {
             setTitle(title);
@@ -211,6 +244,110 @@
         setLogo(getContext().getDrawable(resId));
     }
 
+    /** @hide */
+    public boolean canShowOverflowMenu() {
+        return getVisibility() == VISIBLE && mMenuView != null && mMenuView.isOverflowReserved();
+    }
+
+    /**
+     * Check whether the overflow menu is currently showing. This may not reflect
+     * a pending show operation in progress.
+     *
+     * @return true if the overflow menu is currently showing
+     */
+    public boolean isOverflowMenuShowing() {
+        return mMenuView != null && mMenuView.isOverflowMenuShowing();
+    }
+
+    /** @hide */
+    public boolean isOverflowMenuShowPending() {
+        return mMenuView != null && mMenuView.isOverflowMenuShowPending();
+    }
+
+    /**
+     * Show the overflow items from the associated menu.
+     *
+     * @return true if the menu was able to be shown, false otherwise
+     */
+    public boolean showOverflowMenu() {
+        return mMenuView != null && mMenuView.showOverflowMenu();
+    }
+
+    /**
+     * Hide the overflow items from the associated menu.
+     *
+     * @return true if the menu was able to be hidden, false otherwise
+     */
+    public boolean hideOverflowMenu() {
+        return mMenuView != null && mMenuView.hideOverflowMenu();
+    }
+
+    /** @hide */
+    public void setMenu(MenuBuilder menu, ActionMenuPresenter outerPresenter) {
+        if (menu == null && mMenuView == null) {
+            return;
+        }
+
+        ensureMenuView();
+        final MenuBuilder oldMenu = mMenuView.peekMenu();
+        if (oldMenu == menu) {
+            return;
+        }
+
+        if (oldMenu != null) {
+            oldMenu.removeMenuPresenter(mOuterActionMenuPresenter);
+            oldMenu.removeMenuPresenter(mExpandedMenuPresenter);
+        }
+
+        final Context context = getContext();
+
+        if (mExpandedMenuPresenter == null) {
+            mExpandedMenuPresenter = new ExpandedActionViewMenuPresenter();
+        }
+
+        outerPresenter.setExpandedActionViewsExclusive(true);
+        if (menu != null) {
+            menu.addMenuPresenter(outerPresenter);
+            menu.addMenuPresenter(mExpandedMenuPresenter);
+        } else {
+            outerPresenter.initForMenu(context, null);
+            mExpandedMenuPresenter.initForMenu(context, null);
+            outerPresenter.updateMenuView(true);
+            mExpandedMenuPresenter.updateMenuView(true);
+        }
+        mMenuView.setPresenter(outerPresenter);
+        mOuterActionMenuPresenter = outerPresenter;
+    }
+
+    /**
+     * Dismiss all currently showing popup menus, including overflow or submenus.
+     */
+    public void dismissPopupMenus() {
+        if (mMenuView != null) {
+            mMenuView.dismissPopupMenus();
+        }
+    }
+
+    /** @hide */
+    public boolean isTitleTruncated() {
+        if (mTitleTextView == null) {
+            return false;
+        }
+
+        final Layout titleLayout = mTitleTextView.getLayout();
+        if (titleLayout == null) {
+            return false;
+        }
+
+        final int lineCount = titleLayout.getLineCount();
+        for (int i = 0; i < lineCount; i++) {
+            if (titleLayout.getEllipsisCount(i) > 0) {
+                return true;
+            }
+        }
+        return false;
+    }
+
     /**
      * Set a logo drawable.
      *
@@ -222,9 +359,7 @@
      */
     public void setLogo(Drawable drawable) {
         if (drawable != null) {
-            if (mLogoView == null) {
-                mLogoView = new ImageView(getContext());
-            }
+            ensureLogoView();
             if (mLogoView.getParent() == null) {
                 addSystemView(mLogoView);
             }
@@ -268,8 +403,8 @@
      * @param description Description to set
      */
     public void setLogoDescription(CharSequence description) {
-        if (!TextUtils.isEmpty(description) && mLogoView == null) {
-            mLogoView = new ImageView(getContext());
+        if (!TextUtils.isEmpty(description)) {
+            ensureLogoView();
         }
         if (mLogoView != null) {
             mLogoView.setContentDescription(description);
@@ -285,10 +420,48 @@
         return mLogoView != null ? mLogoView.getContentDescription() : null;
     }
 
+    private void ensureLogoView() {
+        if (mLogoView == null) {
+            mLogoView = new ImageView(getContext());
+        }
+    }
+
     /**
-     * Return the current title displayed in the toolbar.
+     * Check whether this Toolbar is currently hosting an expanded action view.
      *
-     * @return The current title
+     * <p>An action view may be expanded either directly from the
+     * {@link android.view.MenuItem MenuItem} it belongs to or by user action. If the Toolbar
+     * has an expanded action view it can be collapsed using the {@link #collapseActionView()}
+     * method.</p>
+     *
+     * @return true if the Toolbar has an expanded action view
+     */
+    public boolean hasExpandedActionView() {
+        return mExpandedMenuPresenter != null &&
+                mExpandedMenuPresenter.mCurrentExpandedItem != null;
+    }
+
+    /**
+     * Collapse a currently expanded action view. If this Toolbar does not have an
+     * expanded action view this method has no effect.
+     *
+     * <p>An action view may be expanded either directly from the
+     * {@link android.view.MenuItem MenuItem} it belongs to or by user action.</p>
+     *
+     * @see #hasExpandedActionView()
+     */
+    public void collapseActionView() {
+        final MenuItemImpl item = mExpandedMenuPresenter == null ? null :
+                mExpandedMenuPresenter.mCurrentExpandedItem;
+        if (item != null) {
+            item.collapseActionView();
+        }
+    }
+
+    /**
+     * Returns the title of this toolbar.
+     *
+     * @return The current title.
      */
     public CharSequence getTitle() {
         return mTitleText;
@@ -319,6 +492,8 @@
             if (mTitleTextView == null) {
                 final Context context = getContext();
                 mTitleTextView = new TextView(context);
+                mTitleTextView.setSingleLine();
+                mTitleTextView.setEllipsize(TextUtils.TruncateAt.END);
                 mTitleTextView.setTextAppearance(context, mTitleTextAppearance);
             }
             if (mTitleTextView.getParent() == null) {
@@ -365,6 +540,8 @@
             if (mSubtitleTextView == null) {
                 final Context context = getContext();
                 mSubtitleTextView = new TextView(context);
+                mSubtitleTextView.setSingleLine();
+                mSubtitleTextView.setEllipsize(TextUtils.TruncateAt.END);
                 mSubtitleTextView.setTextAppearance(context, mSubtitleTextAppearance);
             }
             if (mSubtitleTextView.getParent() == null) {
@@ -395,6 +572,30 @@
     }
 
     /**
+     * Set a content description for the navigation button if one is present. The content
+     * description will be read via screen readers or other accessibility systems to explain
+     * the action of the navigation button.
+     *
+     * @param description Content description to set
+     */
+    public void setNavigationContentDescription(CharSequence description) {
+        ensureNavButtonView();
+        mNavButtonView.setContentDescription(description);
+    }
+
+    /**
+     * Set a content description for the navigation button if one is present. The content
+     * description will be read via screen readers or other accessibility systems to explain
+     * the action of the navigation button.
+     *
+     * @param resId Resource ID of a content description string to set
+     */
+    public void setNavigationContentDescription(int resId) {
+        ensureNavButtonView();
+        mNavButtonView.setContentDescription(getContext().getText(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
@@ -480,12 +681,19 @@
      * @return The toolbar's Menu
      */
     public Menu getMenu() {
+        ensureMenuView();
+        return mMenuView.getMenu();
+    }
+
+    private void ensureMenuView() {
         if (mMenuView == null) {
             mMenuView = new ActionMenuView(getContext());
             mMenuView.setOnMenuItemClickListener(mMenuViewItemClickListener);
+            final LayoutParams lp = generateDefaultLayoutParams();
+            lp.gravity = Gravity.END | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
+            mMenuView.setLayoutParams(lp);
             addSystemView(mMenuView);
         }
-        return mMenuView.getMenu();
     }
 
     private MenuInflater getMenuInflater() {
@@ -634,7 +842,27 @@
 
     private void ensureNavButtonView() {
         if (mNavButtonView == null) {
-            mNavButtonView = new ImageButton(getContext(), null, R.attr.borderlessButtonStyle);
+            mNavButtonView = new ImageButton(getContext(), null, 0, mNavButtonStyle);
+            final LayoutParams lp = generateDefaultLayoutParams();
+            lp.gravity = Gravity.START | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
+            mNavButtonView.setLayoutParams(lp);
+        }
+    }
+
+    private void ensureCollapseButtonView() {
+        if (mCollapseButtonView == null) {
+            mCollapseButtonView = new ImageButton(getContext(), null, 0, mNavButtonStyle);
+            mCollapseButtonView.setImageDrawable(mCollapseIcon);
+            final LayoutParams lp = generateDefaultLayoutParams();
+            lp.gravity = Gravity.START | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
+            lp.mViewType = LayoutParams.EXPANDED;
+            mCollapseButtonView.setLayoutParams(lp);
+            mCollapseButtonView.setOnClickListener(new OnClickListener() {
+                @Override
+                public void onClick(View v) {
+                    collapseActionView();
+                }
+            });
         }
     }
 
@@ -657,6 +885,27 @@
         super.onRestoreInstanceState(ss.getSuperState());
     }
 
+    private void measureChildConstrained(View child, int parentWidthSpec, int widthUsed,
+            int parentHeightSpec, int heightUsed, int heightConstraint) {
+        final MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams();
+
+        int childWidthSpec = getChildMeasureSpec(parentWidthSpec,
+                mPaddingLeft + mPaddingRight + lp.leftMargin + lp.rightMargin
+                        + widthUsed, lp.width);
+        int childHeightSpec = getChildMeasureSpec(parentHeightSpec,
+                mPaddingTop + mPaddingBottom + lp.topMargin + lp.bottomMargin
+                        + heightUsed, lp.height);
+
+        final int childHeightMode = MeasureSpec.getMode(childHeightSpec);
+        if (childHeightMode != MeasureSpec.EXACTLY && heightConstraint >= 0) {
+            final int size = childHeightMode != MeasureSpec.UNSPECIFIED ?
+                    Math.min(MeasureSpec.getSize(childHeightSpec), heightConstraint) :
+                    heightConstraint;
+            childHeightSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
+        }
+        child.measure(childWidthSpec, childHeightSpec);
+    }
+
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         int width = 0;
@@ -667,18 +916,30 @@
 
         int navWidth = 0;
         if (shouldLayout(mNavButtonView)) {
-            measureChildWithMargins(mNavButtonView, widthMeasureSpec, width, heightMeasureSpec, 0);
+            measureChildConstrained(mNavButtonView, widthMeasureSpec, width, heightMeasureSpec, 0,
+                    mMaxButtonHeight);
             navWidth = mNavButtonView.getMeasuredWidth() + getHorizontalMargins(mNavButtonView);
             height = Math.max(height, mNavButtonView.getMeasuredHeight() +
                     getVerticalMargins(mNavButtonView));
             childState = combineMeasuredStates(childState, mNavButtonView.getMeasuredState());
         }
 
+        if (shouldLayout(mCollapseButtonView)) {
+            measureChildConstrained(mCollapseButtonView, widthMeasureSpec, width,
+                    heightMeasureSpec, 0, mMaxButtonHeight);
+            navWidth = mCollapseButtonView.getMeasuredWidth() +
+                    getHorizontalMargins(mCollapseButtonView);
+            height = Math.max(height, mCollapseButtonView.getMeasuredHeight() +
+                    getVerticalMargins(mCollapseButtonView));
+            childState = combineMeasuredStates(childState, mCollapseButtonView.getMeasuredState());
+        }
+
         width += Math.max(getContentInsetStart(), navWidth);
 
         int menuWidth = 0;
         if (shouldLayout(mMenuView)) {
-            measureChildWithMargins(mMenuView, widthMeasureSpec, width, heightMeasureSpec, 0);
+            measureChildConstrained(mMenuView, widthMeasureSpec, width, heightMeasureSpec, 0,
+                    mMaxButtonHeight);
             menuWidth = mMenuView.getMeasuredWidth() + getHorizontalMargins(mMenuView);
             height = Math.max(height, mMenuView.getMeasuredHeight() +
                     getVerticalMargins(mMenuView));
@@ -687,6 +948,16 @@
 
         width += Math.max(getContentInsetEnd(), menuWidth);
 
+        if (shouldLayout(mExpandedActionView)) {
+            measureChildWithMargins(mExpandedActionView, widthMeasureSpec, width,
+                    heightMeasureSpec, 0);
+            width += mExpandedActionView.getMeasuredWidth() +
+                    getHorizontalMargins(mExpandedActionView);
+            height = Math.max(height, mExpandedActionView.getMeasuredHeight() +
+                    getVerticalMargins(mExpandedActionView));
+            childState = combineMeasuredStates(childState, mExpandedActionView.getMeasuredState());
+        }
+
         if (shouldLayout(mLogoView)) {
             measureChildWithMargins(mLogoView, widthMeasureSpec, width, heightMeasureSpec, 0);
             width += mLogoView.getMeasuredWidth() + getHorizontalMargins(mLogoView);
@@ -723,7 +994,7 @@
         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)) {
+            if (lp.mViewType != LayoutParams.CUSTOM || !shouldLayout(child)) {
                 // We already got all system views above. Skip them and GONE views.
                 continue;
             }
@@ -768,6 +1039,14 @@
             }
         }
 
+        if (shouldLayout(mCollapseButtonView)) {
+            if (isRtl) {
+                right = layoutChildRight(mCollapseButtonView, right);
+            } else {
+                left = layoutChildLeft(mCollapseButtonView, left);
+            }
+        }
+
         if (shouldLayout(mMenuView)) {
             if (isRtl) {
                 left = layoutChildLeft(mMenuView, left);
@@ -779,6 +1058,14 @@
         left = Math.max(left, getContentInsetLeft());
         right = Math.min(right, width - paddingRight - getContentInsetRight());
 
+        if (shouldLayout(mExpandedActionView)) {
+            if (isRtl) {
+                right = layoutChildRight(mExpandedActionView, right);
+            } else {
+                left = layoutChildLeft(mExpandedActionView, left);
+            }
+        }
+
         if (shouldLayout(mLogoView)) {
             if (isRtl) {
                 right = layoutChildRight(mLogoView, right);
@@ -801,40 +1088,42 @@
 
         if (layoutTitle || layoutSubtitle) {
             int titleTop;
+            final View topChild = layoutTitle ? mTitleTextView : mSubtitleTextView;
+            final View bottomChild = layoutSubtitle ? mSubtitleTextView : mTitleTextView;
+            final LayoutParams toplp = (LayoutParams) topChild.getLayoutParams();
+            final LayoutParams bottomlp = (LayoutParams) bottomChild.getLayoutParams();
+
             switch (mGravity & Gravity.VERTICAL_GRAVITY_MASK) {
                 case Gravity.TOP:
-                    titleTop = getPaddingTop();
+                    titleTop = getPaddingTop() + toplp.topMargin + mTitleMarginTop;
                     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;
+                    if (spaceAbove < toplp.topMargin + mTitleMarginTop) {
+                        spaceAbove = toplp.topMargin + mTitleMarginTop;
                     } else {
                         final int spaceBelow = height - paddingBottom - titleHeight -
                                 spaceAbove - paddingTop;
-                        if (spaceBelow < lp.bottomMargin + mTitleMarginBottom) {
+                        if (spaceBelow < toplp.bottomMargin + mTitleMarginBottom) {
                             spaceAbove = Math.max(0, spaceAbove -
-                                    (lp.bottomMargin + mTitleMarginBottom - spaceBelow));
+                                    (bottomlp.bottomMargin + mTitleMarginBottom - spaceBelow));
                         }
                     }
                     titleTop = paddingTop + spaceAbove;
                     break;
                 case Gravity.BOTTOM:
-                    titleTop = height - paddingBottom - titleHeight;
+                    titleTop = height - paddingBottom - bottomlp.bottomMargin - mTitleMarginBottom -
+                            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);
@@ -855,11 +1144,9 @@
             } 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);
@@ -897,7 +1184,7 @@
 
         // 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);
+        addCustomViewsWithGravity(mTempViews, Gravity.CENTER_HORIZONTAL);
         final int centerViewsWidth = getViewListMeasuredWidth(mTempViews);
         final int parentCenter = paddingLeft + (width - paddingLeft - paddingRight) / 2;
         final int halfCenterViewsWidth = centerViewsWidth / 2;
@@ -1007,17 +1294,16 @@
             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) &&
+                if (lp.mViewType == LayoutParams.CUSTOM && 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) &&
+                if (lp.mViewType == LayoutParams.CUSTOM && shouldLayout(child) &&
                         getChildHorizontalGravity(lp.gravity) == absGrav) {
                     views.add(child);
                 }
@@ -1054,14 +1340,16 @@
     }
 
     @Override
-    public ViewGroup.LayoutParams generateLayoutParams(AttributeSet attrs) {
-        return super.generateLayoutParams(attrs);
+    public LayoutParams generateLayoutParams(AttributeSet attrs) {
+        return new LayoutParams(getContext(), attrs);
     }
 
     @Override
-    protected ViewGroup.LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
+    protected LayoutParams generateLayoutParams(ViewGroup.LayoutParams p) {
         if (p instanceof LayoutParams) {
             return new LayoutParams((LayoutParams) p);
+        } else if (p instanceof ActionBar.LayoutParams) {
+            return new LayoutParams((ActionBar.LayoutParams) p);
         } else if (p instanceof MarginLayoutParams) {
             return new LayoutParams((MarginLayoutParams) p);
         } else {
@@ -1070,7 +1358,7 @@
     }
 
     @Override
-    protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
+    protected LayoutParams generateDefaultLayoutParams() {
         return new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
     }
 
@@ -1083,6 +1371,25 @@
         return ((LayoutParams) child.getLayoutParams()).mViewType == LayoutParams.CUSTOM;
     }
 
+    /** @hide */
+    public DecorToolbar getWrapper() {
+        if (mWrapper == null) {
+            mWrapper = new ToolbarWidgetWrapper(this);
+        }
+        return mWrapper;
+    }
+
+    private void setChildVisibilityForExpandedActionView(boolean expand) {
+        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.EXPANDED && child != mMenuView) {
+                child.setVisibility(expand ? GONE : VISIBLE);
+            }
+        }
+    }
+
     /**
      * Interface responsible for receiving menu item click events if the items themselves
      * do not have individual item click listeners.
@@ -1103,44 +1410,15 @@
      *
      * @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;
-
+    public static class LayoutParams extends ActionBar.LayoutParams {
         static final int CUSTOM = 0;
         static final int SYSTEM = 1;
+        static final int EXPANDED = 2;
 
         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) {
@@ -1160,7 +1438,11 @@
         public LayoutParams(LayoutParams source) {
             super(source);
 
-            this.gravity = source.gravity;
+            mViewType = source.mViewType;
+        }
+
+        public LayoutParams(ActionBar.LayoutParams source) {
+            super(source);
         }
 
         public LayoutParams(MarginLayoutParams source) {
@@ -1199,4 +1481,126 @@
             }
         };
     }
+
+    private class ExpandedActionViewMenuPresenter implements MenuPresenter {
+        MenuBuilder mMenu;
+        MenuItemImpl mCurrentExpandedItem;
+
+        @Override
+        public void initForMenu(Context context, MenuBuilder menu) {
+            // Clear the expanded action view when menus change.
+            if (mMenu != null && mCurrentExpandedItem != null) {
+                mMenu.collapseItemActionView(mCurrentExpandedItem);
+            }
+            mMenu = menu;
+        }
+
+        @Override
+        public MenuView getMenuView(ViewGroup root) {
+            return null;
+        }
+
+        @Override
+        public void updateMenuView(boolean cleared) {
+            // Make sure the expanded item we have is still there.
+            if (mCurrentExpandedItem != null) {
+                boolean found = false;
+
+                if (mMenu != null) {
+                    final int count = mMenu.size();
+                    for (int i = 0; i < count; i++) {
+                        final MenuItem item = mMenu.getItem(i);
+                        if (item == mCurrentExpandedItem) {
+                            found = true;
+                            break;
+                        }
+                    }
+                }
+
+                if (!found) {
+                    // The item we had expanded disappeared. Collapse.
+                    collapseItemActionView(mMenu, mCurrentExpandedItem);
+                }
+            }
+        }
+
+        @Override
+        public void setCallback(Callback cb) {
+        }
+
+        @Override
+        public boolean onSubMenuSelected(SubMenuBuilder subMenu) {
+            return false;
+        }
+
+        @Override
+        public void onCloseMenu(MenuBuilder menu, boolean allMenusAreClosing) {
+        }
+
+        @Override
+        public boolean flagActionItems() {
+            return false;
+        }
+
+        @Override
+        public boolean expandItemActionView(MenuBuilder menu, MenuItemImpl item) {
+            ensureCollapseButtonView();
+            if (mCollapseButtonView.getParent() != Toolbar.this) {
+                addView(mCollapseButtonView);
+            }
+            mExpandedActionView = item.getActionView();
+            mCurrentExpandedItem = item;
+            if (mExpandedActionView.getParent() != Toolbar.this) {
+                final LayoutParams lp = generateDefaultLayoutParams();
+                lp.gravity = Gravity.START | (mButtonGravity & Gravity.VERTICAL_GRAVITY_MASK);
+                lp.mViewType = LayoutParams.EXPANDED;
+                mExpandedActionView.setLayoutParams(lp);
+                addView(mExpandedActionView);
+            }
+
+            setChildVisibilityForExpandedActionView(true);
+            requestLayout();
+            item.setActionViewExpanded(true);
+
+            if (mExpandedActionView instanceof CollapsibleActionView) {
+                ((CollapsibleActionView) mExpandedActionView).onActionViewExpanded();
+            }
+
+            return true;
+        }
+
+        @Override
+        public boolean collapseItemActionView(MenuBuilder menu, MenuItemImpl item) {
+            // Do this before detaching the actionview from the hierarchy, in case
+            // it needs to dismiss the soft keyboard, etc.
+            if (mExpandedActionView instanceof CollapsibleActionView) {
+                ((CollapsibleActionView) mExpandedActionView).onActionViewCollapsed();
+            }
+
+            removeView(mExpandedActionView);
+            removeView(mCollapseButtonView);
+            mExpandedActionView = null;
+
+            setChildVisibilityForExpandedActionView(false);
+            mCurrentExpandedItem = null;
+            requestLayout();
+            item.setActionViewExpanded(false);
+
+            return true;
+        }
+
+        @Override
+        public int getId() {
+            return 0;
+        }
+
+        @Override
+        public Parcelable onSaveInstanceState() {
+            return null;
+        }
+
+        @Override
+        public void onRestoreInstanceState(Parcelable state) {
+        }
+    }
 }
diff --git a/core/java/com/android/internal/app/ProcessStats.java b/core/java/com/android/internal/app/ProcessStats.java
index 41f3337..7e11850 100644
--- a/core/java/com/android/internal/app/ProcessStats.java
+++ b/core/java/com/android/internal/app/ProcessStats.java
@@ -1100,7 +1100,7 @@
 
     public boolean evaluateSystemProperties(boolean update) {
         boolean changed = false;
-        String runtime = SystemProperties.get("persist.sys.dalvik.vm.lib.1",
+        String runtime = SystemProperties.get("persist.sys.dalvik.vm.lib.2",
                 VMRuntime.getRuntime().vmLibrary());
         if (!Objects.equals(runtime, mRuntime)) {
             changed = true;
diff --git a/core/java/com/android/internal/app/WindowDecorActionBar.java b/core/java/com/android/internal/app/WindowDecorActionBar.java
index a238ae3..a0c75a6 100644
--- a/core/java/com/android/internal/app/WindowDecorActionBar.java
+++ b/core/java/com/android/internal/app/WindowDecorActionBar.java
@@ -18,7 +18,10 @@
 
 import android.animation.ValueAnimator;
 import android.content.res.TypedArray;
+import android.view.ViewGroup;
 import android.view.ViewParent;
+import android.widget.AdapterView;
+import android.widget.Toolbar;
 import com.android.internal.R;
 import com.android.internal.view.ActionBarPolicy;
 import com.android.internal.view.menu.MenuBuilder;
@@ -28,6 +31,7 @@
 import com.android.internal.widget.ActionBarContextView;
 import com.android.internal.widget.ActionBarOverlayLayout;
 import com.android.internal.widget.ActionBarView;
+import com.android.internal.widget.DecorToolbar;
 import com.android.internal.widget.ScrollingTabContainerView;
 
 import android.animation.Animator;
@@ -55,6 +59,7 @@
 import android.view.accessibility.AccessibilityEvent;
 import android.view.animation.AnimationUtils;
 import android.widget.SpinnerAdapter;
+import com.android.internal.widget.ToolbarWidgetWrapper;
 
 import java.lang.ref.WeakReference;
 import java.util.ArrayList;
@@ -77,7 +82,7 @@
 
     private ActionBarOverlayLayout mOverlayLayout;
     private ActionBarContainer mContainerView;
-    private ActionBarView mActionView;
+    private DecorToolbar mDecorToolbar;
     private ActionBarContextView mContextView;
     private ActionBarContainer mSplitView;
     private View mContentView;
@@ -187,7 +192,7 @@
         if (mOverlayLayout != null) {
             mOverlayLayout.setActionBarVisibilityCallback(this);
         }
-        mActionView = (ActionBarView) decor.findViewById(com.android.internal.R.id.action_bar);
+        mDecorToolbar = getDecorToolbar(decor.findViewById(com.android.internal.R.id.action_bar));
         mContextView = (ActionBarContextView) decor.findViewById(
                 com.android.internal.R.id.action_context_bar);
         mContainerView = (ActionBarContainer) decor.findViewById(
@@ -195,18 +200,17 @@
         mSplitView = (ActionBarContainer) decor.findViewById(
                 com.android.internal.R.id.split_action_bar);
 
-        if (mActionView == null || mContextView == null || mContainerView == null) {
+        if (mDecorToolbar == null || mContextView == null || mContainerView == null) {
             throw new IllegalStateException(getClass().getSimpleName() + " can only be used " +
                     "with a compatible window decor layout");
         }
 
-        mContext = mActionView.getContext();
-        mActionView.setContextView(mContextView);
-        mContextDisplayMode = mActionView.isSplitActionBar() ?
+        mContext = mDecorToolbar.getContext();
+        mContextDisplayMode = mDecorToolbar.isSplit() ?
                 CONTEXT_DISPLAY_SPLIT : CONTEXT_DISPLAY_NORMAL;
 
         // This was initially read from the action bar style
-        final int current = mActionView.getDisplayOptions();
+        final int current = mDecorToolbar.getDisplayOptions();
         final boolean homeAsUp = (current & DISPLAY_HOME_AS_UP) != 0;
         if (homeAsUp) {
             mDisplayHomeAsUpSet = true;
@@ -225,6 +229,17 @@
         a.recycle();
     }
 
+    private DecorToolbar getDecorToolbar(View view) {
+        if (view instanceof DecorToolbar) {
+            return (DecorToolbar) view;
+        } else if (view instanceof Toolbar) {
+            return ((Toolbar) view).getWrapper();
+        } else {
+            throw new IllegalStateException("Can't make a decor toolbar out of " +
+                    view.getClass().getSimpleName());
+        }
+    }
+
     public void onConfigurationChanged(Configuration newConfig) {
         setHasEmbeddedTabs(ActionBarPolicy.get(mContext).hasEmbeddedTabs());
     }
@@ -233,11 +248,11 @@
         mHasEmbeddedTabs = hasEmbeddedTabs;
         // Switch tab layout configuration if needed
         if (!mHasEmbeddedTabs) {
-            mActionView.setEmbeddedTabView(null);
+            mDecorToolbar.setEmbeddedTabView(null);
             mContainerView.setTabContainer(mTabScrollView);
         } else {
             mContainerView.setTabContainer(null);
-            mActionView.setEmbeddedTabView(mTabScrollView);
+            mDecorToolbar.setEmbeddedTabView(mTabScrollView);
         }
         final boolean isInTabMode = getNavigationMode() == NAVIGATION_MODE_TABS;
         if (mTabScrollView != null) {
@@ -250,7 +265,7 @@
                 mTabScrollView.setVisibility(View.GONE);
             }
         }
-        mActionView.setCollapsable(!mHasEmbeddedTabs && isInTabMode);
+        mDecorToolbar.setCollapsible(!mHasEmbeddedTabs && isInTabMode);
         mOverlayLayout.setHasNonEmbeddedTabs(!mHasEmbeddedTabs && isInTabMode);
     }
 
@@ -263,7 +278,7 @@
 
         if (mHasEmbeddedTabs) {
             tabScroller.setVisibility(View.VISIBLE);
-            mActionView.setEmbeddedTabView(tabScroller);
+            mDecorToolbar.setEmbeddedTabView(tabScroller);
         } else {
             if (getNavigationMode() == NAVIGATION_MODE_TABS) {
                 tabScroller.setVisibility(View.VISIBLE);
@@ -326,7 +341,8 @@
 
     @Override
     public void setCustomView(int resId) {
-        setCustomView(LayoutInflater.from(getThemedContext()).inflate(resId, mActionView, false));
+        setCustomView(LayoutInflater.from(getThemedContext()).inflate(resId,
+                (ViewGroup) mDecorToolbar, false));
     }
 
     @Override
@@ -356,7 +372,7 @@
 
     @Override
     public void setHomeButtonEnabled(boolean enable) {
-        mActionView.setHomeButtonEnabled(enable);
+        mDecorToolbar.setHomeButtonEnabled(enable);
     }
 
     @Override
@@ -370,12 +386,12 @@
     }
 
     public void setSelectedNavigationItem(int position) {
-        switch (mActionView.getNavigationMode()) {
+        switch (mDecorToolbar.getNavigationMode()) {
         case NAVIGATION_MODE_TABS:
             selectTab(mTabs.get(position));
             break;
         case NAVIGATION_MODE_LIST:
-            mActionView.setDropdownSelectedPosition(position);
+            mDecorToolbar.setDropdownSelectedPosition(position);
             break;
         default:
             throw new IllegalStateException(
@@ -399,26 +415,26 @@
     }
 
     public void setTitle(CharSequence title) {
-        mActionView.setTitle(title);
+        mDecorToolbar.setTitle(title);
     }
 
     public void setSubtitle(CharSequence subtitle) {
-        mActionView.setSubtitle(subtitle);
+        mDecorToolbar.setSubtitle(subtitle);
     }
 
     public void setDisplayOptions(int options) {
         if ((options & DISPLAY_HOME_AS_UP) != 0) {
             mDisplayHomeAsUpSet = true;
         }
-        mActionView.setDisplayOptions(options);
+        mDecorToolbar.setDisplayOptions(options);
     }
 
     public void setDisplayOptions(int options, int mask) {
-        final int current = mActionView.getDisplayOptions(); 
+        final int current = mDecorToolbar.getDisplayOptions();
         if ((mask & DISPLAY_HOME_AS_UP) != 0) {
             mDisplayHomeAsUpSet = true;
         }
-        mActionView.setDisplayOptions((options & mask) | (current & ~mask));
+        mDecorToolbar.setDisplayOptions((options & mask) | (current & ~mask));
     }
 
     public void setBackgroundDrawable(Drawable d) {
@@ -436,23 +452,23 @@
     }
 
     public View getCustomView() {
-        return mActionView.getCustomNavigationView();
+        return mDecorToolbar.getCustomView();
     }
 
     public CharSequence getTitle() {
-        return mActionView.getTitle();
+        return mDecorToolbar.getTitle();
     }
 
     public CharSequence getSubtitle() {
-        return mActionView.getSubtitle();
+        return mDecorToolbar.getSubtitle();
     }
 
     public int getNavigationMode() {
-        return mActionView.getNavigationMode();
+        return mDecorToolbar.getNavigationMode();
     }
 
     public int getDisplayOptions() {
-        return mActionView.getDisplayOptions();
+        return mDecorToolbar.getDisplayOptions();
     }
 
     public ActionMode startActionMode(ActionMode.Callback callback) {
@@ -572,7 +588,7 @@
             return;
         }
 
-        final FragmentTransaction trans = mActionView.isInEditMode() ? null :
+        final FragmentTransaction trans = ((View) mDecorToolbar).isInEditMode() ? null :
                 mActivity.getFragmentManager().beginTransaction().disallowAddToBackStack();
 
         if (mSelectedTab == tab) {
@@ -828,13 +844,18 @@
             hideForActionMode();
         }
 
-        mActionView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
+        mDecorToolbar.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
         mContextView.animateToVisibility(toActionMode ? View.VISIBLE : View.GONE);
-        if (mTabScrollView != null && !mActionView.hasEmbeddedTabs() && mActionView.isCollapsed()) {
+        if (mTabScrollView != null && !mDecorToolbar.hasEmbeddedTabs() &&
+                isCollapsed((View) mDecorToolbar)) {
             mTabScrollView.animateToVisibility(toActionMode ? View.GONE : View.VISIBLE);
         }
     }
 
+    private boolean isCollapsed(View view) {
+        return view == null || view.getVisibility() == View.GONE || view.getMeasuredHeight() == 0;
+    }
+
     public Context getThemedContext() {
         if (mThemedContext == null) {
             TypedValue outValue = new TypedValue();
@@ -854,27 +875,27 @@
     
     @Override
     public boolean isTitleTruncated() {
-        return mActionView != null && mActionView.isTitleTruncated();
+        return mDecorToolbar != null && mDecorToolbar.isTitleTruncated();
     }
 
     @Override
     public void setHomeAsUpIndicator(Drawable indicator) {
-        mActionView.setHomeAsUpIndicator(indicator);
+        mDecorToolbar.setNavigationIcon(indicator);
     }
 
     @Override
     public void setHomeAsUpIndicator(int resId) {
-        mActionView.setHomeAsUpIndicator(resId);
+        mDecorToolbar.setNavigationIcon(resId);
     }
 
     @Override
     public void setHomeActionContentDescription(CharSequence description) {
-        mActionView.setHomeActionContentDescription(description);
+        mDecorToolbar.setNavigationContentDescription(description);
     }
 
     @Override
     public void setHomeActionContentDescription(int resId) {
-        mActionView.setHomeActionContentDescription(resId);
+        mDecorToolbar.setNavigationContentDescription(resId);
     }
 
     @Override
@@ -938,7 +959,8 @@
 
             // Clear out the context mode views after the animation finishes
             mContextView.closeMode();
-            mActionView.sendAccessibilityEvent(AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+            ((View) mDecorToolbar).sendAccessibilityEvent(
+                    AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
             mOverlayLayout.setHideOnContentScrollEnabled(mHideOnContentScroll);
 
             mActionMode = null;
@@ -1178,28 +1200,27 @@
 
     @Override
     public void setCustomView(View view) {
-        mActionView.setCustomNavigationView(view);
+        mDecorToolbar.setCustomView(view);
     }
 
     @Override
     public void setCustomView(View view, LayoutParams layoutParams) {
         view.setLayoutParams(layoutParams);
-        mActionView.setCustomNavigationView(view);
+        mDecorToolbar.setCustomView(view);
     }
 
     @Override
     public void setListNavigationCallbacks(SpinnerAdapter adapter, OnNavigationListener callback) {
-        mActionView.setDropdownAdapter(adapter);
-        mActionView.setCallback(callback);
+        mDecorToolbar.setDropdownParams(adapter, new NavItemSelectedListener(callback));
     }
 
     @Override
     public int getSelectedNavigationIndex() {
-        switch (mActionView.getNavigationMode()) {
+        switch (mDecorToolbar.getNavigationMode()) {
             case NAVIGATION_MODE_TABS:
                 return mSelectedTab != null ? mSelectedTab.getPosition() : -1;
             case NAVIGATION_MODE_LIST:
-                return mActionView.getDropdownSelectedPosition();
+                return mDecorToolbar.getDropdownSelectedPosition();
             default:
                 return -1;
         }
@@ -1207,12 +1228,11 @@
 
     @Override
     public int getNavigationItemCount() {
-        switch (mActionView.getNavigationMode()) {
+        switch (mDecorToolbar.getNavigationMode()) {
             case NAVIGATION_MODE_TABS:
                 return mTabs.size();
             case NAVIGATION_MODE_LIST:
-                SpinnerAdapter adapter = mActionView.getDropdownAdapter();
-                return adapter != null ? adapter.getCount() : 0;
+                return mDecorToolbar.getDropdownItemCount();
             default:
                 return 0;
         }
@@ -1225,7 +1245,7 @@
 
     @Override
     public void setNavigationMode(int mode) {
-        final int oldMode = mActionView.getNavigationMode();
+        final int oldMode = mDecorToolbar.getNavigationMode();
         switch (oldMode) {
             case NAVIGATION_MODE_TABS:
                 mSavedTabPosition = getSelectedNavigationIndex();
@@ -1238,7 +1258,7 @@
                 mOverlayLayout.requestFitSystemWindows();
             }
         }
-        mActionView.setNavigationMode(mode);
+        mDecorToolbar.setNavigationMode(mode);
         switch (mode) {
             case NAVIGATION_MODE_TABS:
                 ensureTabsExist();
@@ -1249,7 +1269,7 @@
                 }
                 break;
         }
-        mActionView.setCollapsable(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs);
+        mDecorToolbar.setCollapsible(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs);
         mOverlayLayout.setHasNonEmbeddedTabs(mode == NAVIGATION_MODE_TABS && !mHasEmbeddedTabs);
     }
 
@@ -1261,30 +1281,30 @@
 
     @Override
     public void setIcon(int resId) {
-        mActionView.setIcon(resId);
+        mDecorToolbar.setIcon(resId);
     }
 
     @Override
     public void setIcon(Drawable icon) {
-        mActionView.setIcon(icon);
+        mDecorToolbar.setIcon(icon);
     }
 
     public boolean hasIcon() {
-        return mActionView.hasIcon();
+        return mDecorToolbar.hasIcon();
     }
 
     @Override
     public void setLogo(int resId) {
-        mActionView.setLogo(resId);
+        mDecorToolbar.setLogo(resId);
     }
 
     @Override
     public void setLogo(Drawable logo) {
-        mActionView.setLogo(logo);
+        mDecorToolbar.setLogo(logo);
     }
 
     public boolean hasLogo() {
-        return mActionView.hasLogo();
+        return mDecorToolbar.hasLogo();
     }
 
     public void setDefaultDisplayHomeAsUpEnabled(boolean enable) {
@@ -1292,4 +1312,24 @@
             setDisplayHomeAsUpEnabled(enable);
         }
     }
+
+    static class NavItemSelectedListener implements AdapterView.OnItemSelectedListener {
+        private final OnNavigationListener mListener;
+
+        public NavItemSelectedListener(OnNavigationListener listener) {
+            mListener = listener;
+        }
+
+        @Override
+        public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
+            if (mListener != null) {
+                mListener.onNavigationItemSelected(position, id);
+            }
+        }
+
+        @Override
+        public void onNothingSelected(AdapterView<?> parent) {
+            // Do nothing
+        }
+    }
 }
diff --git a/core/java/com/android/internal/widget/AbsActionBarView.java b/core/java/com/android/internal/widget/AbsActionBarView.java
index 183478f..9e7ff93 100644
--- a/core/java/com/android/internal/widget/AbsActionBarView.java
+++ b/core/java/com/android/internal/widget/AbsActionBarView.java
@@ -34,7 +34,7 @@
 public abstract class AbsActionBarView extends ViewGroup {
     protected ActionMenuView mMenuView;
     protected ActionMenuPresenter mActionMenuPresenter;
-    protected ActionBarContainer mSplitView;
+    protected ViewGroup mSplitView;
     protected boolean mSplitActionBar;
     protected boolean mSplitWhenNarrow;
     protected int mContentHeight;
@@ -74,7 +74,7 @@
         setContentHeight(a.getLayoutDimension(R.styleable.ActionBar_height, 0));
         a.recycle();
         if (mSplitWhenNarrow) {
-            setSplitActionBar(getContext().getResources().getBoolean(
+            setSplitToolbar(getContext().getResources().getBoolean(
                     com.android.internal.R.bool.split_action_bar_is_narrow));
         }
         if (mActionMenuPresenter != null) {
@@ -86,7 +86,7 @@
      * Sets whether the bar should be split right now, no questions asked.
      * @param split true if the bar should split
      */
-    public void setSplitActionBar(boolean split) {
+    public void setSplitToolbar(boolean split) {
         mSplitActionBar = split;
     }
 
@@ -107,7 +107,7 @@
         return mContentHeight;
     }
 
-    public void setSplitView(ActionBarContainer splitView) {
+    public void setSplitView(ViewGroup splitView) {
         mSplitView = splitView;
     }
 
@@ -214,6 +214,10 @@
         return mActionMenuPresenter != null && mActionMenuPresenter.isOverflowReserved();
     }
 
+    public boolean canShowOverflowMenu() {
+        return isOverflowReserved() && getVisibility() == VISIBLE;
+    }
+
     public void dismissPopupMenus() {
         if (mActionMenuPresenter != null) {
             mActionMenuPresenter.dismissPopupMenus();
diff --git a/core/java/com/android/internal/widget/ActionBarContainer.java b/core/java/com/android/internal/widget/ActionBarContainer.java
index ed07514..790b611 100644
--- a/core/java/com/android/internal/widget/ActionBarContainer.java
+++ b/core/java/com/android/internal/widget/ActionBarContainer.java
@@ -36,7 +36,7 @@
 public class ActionBarContainer extends FrameLayout {
     private boolean mIsTransitioning;
     private View mTabContainer;
-    private ActionBarView mActionBarView;
+    private View mActionBarView;
 
     private Drawable mBackground;
     private Drawable mStackedBackground;
@@ -76,7 +76,7 @@
     @Override
     public void onFinishInflate() {
         super.onFinishInflate();
-        mActionBarView = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
+        mActionBarView = findViewById(com.android.internal.R.id.action_bar);
     }
 
     public void setPrimaryBackground(Drawable bg) {
@@ -251,6 +251,10 @@
         return null;
     }
 
+    private boolean isCollapsed(View view) {
+        return view == null || view.getVisibility() == GONE || view.getMeasuredHeight() == 0;
+    }
+
     @Override
     public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         if (mActionBarView == null &&
@@ -263,7 +267,7 @@
         if (mActionBarView == null) return;
 
         final LayoutParams lp = (LayoutParams) mActionBarView.getLayoutParams();
-        final int actionBarViewHeight = mActionBarView.isCollapsed() ? 0 :
+        final int actionBarViewHeight = isCollapsed(mActionBarView) ? 0 :
                 mActionBarView.getMeasuredHeight() + lp.topMargin + lp.bottomMargin;
 
         if (mTabContainer != null && mTabContainer.getVisibility() != GONE) {
@@ -298,9 +302,8 @@
             }
         } else {
             if (mBackground != null) {
-                final ActionBarView actionBarView = mActionBarView;
-                mBackground.setBounds(actionBarView.getLeft(), actionBarView.getTop(),
-                        actionBarView.getRight(), actionBarView.getBottom());
+                mBackground.setBounds(mActionBarView.getLeft(), mActionBarView.getTop(),
+                        mActionBarView.getRight(), mActionBarView.getBottom());
                 needsInvalidate = true;
             }
             mIsStacked = hasTabs;
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index e10070f..6ff77a0 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -83,7 +83,7 @@
 
         final TypedArray a = context.obtainStyledAttributes(
                 attrs, R.styleable.ActionMode, defStyleAttr, defStyleRes);
-        setBackgroundDrawable(a.getDrawable(
+        setBackground(a.getDrawable(
                 com.android.internal.R.styleable.ActionMode_background));
         mTitleStyleRes = a.getResourceId(
                 com.android.internal.R.styleable.ActionMode_titleTextStyle, 0);
@@ -109,7 +109,7 @@
     }
 
     @Override
-    public void setSplitActionBar(boolean split) {
+    public void setSplitToolbar(boolean split) {
         if (mSplitActionBar != split) {
             if (mActionMenuPresenter != null) {
                 // Mode is already active; move everything over and adjust the menu itself.
@@ -137,7 +137,7 @@
                     mSplitView.addView(mMenuView, layoutParams);
                 }
             }
-            super.setSplitActionBar(split);
+            super.setSplitToolbar(split);
         }
     }
 
diff --git a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
index 7ab4bed..8a9cb22 100644
--- a/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
+++ b/core/java/com/android/internal/widget/ActionBarOverlayLayout.java
@@ -39,6 +39,7 @@
 import android.view.Window;
 import android.view.WindowInsets;
 import android.widget.OverScroller;
+import android.widget.Toolbar;
 import com.android.internal.view.menu.MenuPresenter;
 
 /**
@@ -59,7 +60,7 @@
     private ActionBarContainer mActionBarTop;
 
     // Some interior UI elements.
-    private ActionBarView mActionBarView;
+    private DecorToolbar mDecorToolbar;
 
     // Content overlay drawable - generally the action bar's shadow
     private Drawable mWindowContentOverlay;
@@ -401,7 +402,7 @@
             topInset = mActionBarTop.getMeasuredHeight();
         }
 
-        if (mActionBarView.isSplitActionBar()) {
+        if (mDecorToolbar.isSplit()) {
             // If action bar is split, adjust bottom insets for it.
             if (mActionBarBottom != null) {
                 if (stable) {
@@ -563,12 +564,23 @@
             mContent = findViewById(com.android.internal.R.id.content);
             mActionBarTop = (ActionBarContainer) findViewById(
                     com.android.internal.R.id.action_bar_container);
-            mActionBarView = (ActionBarView) findViewById(com.android.internal.R.id.action_bar);
+            mDecorToolbar = getDecorToolbar(findViewById(com.android.internal.R.id.action_bar));
             mActionBarBottom = (ActionBarContainer) findViewById(
                     com.android.internal.R.id.split_action_bar);
         }
     }
 
+    private DecorToolbar getDecorToolbar(View view) {
+        if (view instanceof DecorToolbar) {
+            return (DecorToolbar) view;
+        } else if (view instanceof Toolbar) {
+            return ((Toolbar) view).getWrapper();
+        } else {
+            throw new IllegalStateException("Can't make a decor toolbar out of " +
+                    view.getClass().getSimpleName());
+        }
+    }
+
     public void setHideOnContentScrollEnabled(boolean hideOnContentScroll) {
         if (hideOnContentScroll != mHideOnContentScroll) {
             mHideOnContentScroll = hideOnContentScroll;
@@ -648,9 +660,9 @@
             final int action = event.getAction();
 
             // Collapse any expanded action views.
-            if (mActionBarView != null && mActionBarView.hasExpandedActionView()) {
+            if (mDecorToolbar != null && mDecorToolbar.hasExpandedActionView()) {
                 if (action == KeyEvent.ACTION_UP) {
-                    mActionBarView.collapseActionView();
+                    mDecorToolbar.collapseActionView();
                 }
                 return true;
             }
@@ -662,19 +674,19 @@
     @Override
     public void setWindowCallback(Window.Callback cb) {
         pullChildren();
-        mActionBarView.setWindowCallback(cb);
+        mDecorToolbar.setWindowCallback(cb);
     }
 
     @Override
     public void setWindowTitle(CharSequence title) {
         pullChildren();
-        mActionBarView.setWindowTitle(title);
+        mDecorToolbar.setWindowTitle(title);
     }
 
     @Override
     public CharSequence getTitle() {
         pullChildren();
-        return mActionBarView.getTitle();
+        return mDecorToolbar.getTitle();
     }
 
     @Override
@@ -682,10 +694,10 @@
         pullChildren();
         switch (windowFeature) {
             case Window.FEATURE_PROGRESS:
-                mActionBarView.initProgress();
+                mDecorToolbar.initProgress();
                 break;
             case Window.FEATURE_INDETERMINATE_PROGRESS:
-                mActionBarView.initIndeterminateProgress();
+                mDecorToolbar.initIndeterminateProgress();
                 break;
             case Window.FEATURE_ACTION_BAR_OVERLAY:
                 setOverlayMode(true);
@@ -704,15 +716,15 @@
         }
         if (splitActionBar) {
             pullChildren();
-            if (mActionBarBottom != null) {
-                mActionBarView.setSplitView(mActionBarBottom);
-                mActionBarView.setSplitActionBar(splitActionBar);
-                mActionBarView.setSplitWhenNarrow(splitWhenNarrow);
+            if (mActionBarBottom != null && mDecorToolbar.canSplit()) {
+                mDecorToolbar.setSplitView(mActionBarBottom);
+                mDecorToolbar.setSplitToolbar(splitActionBar);
+                mDecorToolbar.setSplitWhenNarrow(splitWhenNarrow);
 
                 final ActionBarContextView cab = (ActionBarContextView) findViewById(
                         com.android.internal.R.id.action_context_bar);
                 cab.setSplitView(mActionBarBottom);
-                cab.setSplitActionBar(splitActionBar);
+                cab.setSplitToolbar(splitActionBar);
                 cab.setSplitWhenNarrow(splitWhenNarrow);
             } else if (splitActionBar) {
                 Log.e(TAG, "Requested split action bar with " +
@@ -724,91 +736,91 @@
     @Override
     public boolean hasIcon() {
         pullChildren();
-        return mActionBarView.hasIcon();
+        return mDecorToolbar.hasIcon();
     }
 
     @Override
     public boolean hasLogo() {
         pullChildren();
-        return mActionBarView.hasLogo();
+        return mDecorToolbar.hasLogo();
     }
 
     @Override
     public void setIcon(int resId) {
         pullChildren();
-        mActionBarView.setIcon(resId);
+        mDecorToolbar.setIcon(resId);
     }
 
     @Override
     public void setIcon(Drawable d) {
         pullChildren();
-        mActionBarView.setIcon(d);
+        mDecorToolbar.setIcon(d);
     }
 
     @Override
     public void setLogo(int resId) {
         pullChildren();
-        mActionBarView.setLogo(resId);
+        mDecorToolbar.setLogo(resId);
     }
 
     @Override
     public boolean canShowOverflowMenu() {
         pullChildren();
-        return mActionBarView.isOverflowReserved() && mActionBarView.getVisibility() == VISIBLE;
+        return mDecorToolbar.canShowOverflowMenu();
     }
 
     @Override
     public boolean isOverflowMenuShowing() {
         pullChildren();
-        return mActionBarView.isOverflowMenuShowing();
+        return mDecorToolbar.isOverflowMenuShowing();
     }
 
     @Override
     public boolean isOverflowMenuShowPending() {
         pullChildren();
-        return mActionBarView.isOverflowMenuShowPending();
+        return mDecorToolbar.isOverflowMenuShowPending();
     }
 
     @Override
     public boolean showOverflowMenu() {
         pullChildren();
-        return mActionBarView.showOverflowMenu();
+        return mDecorToolbar.showOverflowMenu();
     }
 
     @Override
     public boolean hideOverflowMenu() {
         pullChildren();
-        return mActionBarView.hideOverflowMenu();
+        return mDecorToolbar.hideOverflowMenu();
     }
 
     @Override
     public void setMenuPrepared() {
         pullChildren();
-        mActionBarView.setMenuPrepared();
+        mDecorToolbar.setMenuPrepared();
     }
 
     @Override
     public void setMenu(Menu menu, MenuPresenter.Callback cb) {
         pullChildren();
-        mActionBarView.setMenu(menu, cb);
+        mDecorToolbar.setMenu(menu, cb);
     }
 
     @Override
     public void saveToolbarHierarchyState(SparseArray<Parcelable> toolbarStates) {
         pullChildren();
-        mActionBarView.saveHierarchyState(toolbarStates);
+        mDecorToolbar.saveHierarchyState(toolbarStates);
     }
 
     @Override
     public void restoreToolbarHierarchyState(SparseArray<Parcelable> toolbarStates) {
         pullChildren();
-        mActionBarView.restoreHierarchyState(toolbarStates);
+        mDecorToolbar.restoreHierarchyState(toolbarStates);
     }
 
     @Override
     public void dismissPopups() {
         pullChildren();
-        mActionBarView.dismissPopupMenus();
+        mDecorToolbar.dismissPopupMenus();
     }
 
     public static class LayoutParams extends MarginLayoutParams {
diff --git a/core/java/com/android/internal/widget/ActionBarView.java b/core/java/com/android/internal/widget/ActionBarView.java
index 60631b9..af82778 100644
--- a/core/java/com/android/internal/widget/ActionBarView.java
+++ b/core/java/com/android/internal/widget/ActionBarView.java
@@ -18,7 +18,6 @@
 
 import android.animation.LayoutTransition;
 import android.app.ActionBar;
-import android.app.ActionBar.OnNavigationListener;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
@@ -63,7 +62,7 @@
 /**
  * @hide
  */
-public class ActionBarView extends AbsActionBarView {
+public class ActionBarView extends AbsActionBarView implements DecorToolbar {
     private static final String TAG = "ActionBarView";
 
     /**
@@ -117,8 +116,7 @@
 
     private boolean mUserTitle;
     private boolean mIncludeTabs;
-    private boolean mIsCollapsable;
-    private boolean mIsCollapsed;
+    private boolean mIsCollapsible;
     private boolean mWasHomeEnabled; // Was it enabled before action view expansion?
 
     private MenuBuilder mOptionsMenu;
@@ -129,7 +127,7 @@
     private ActionMenuItem mLogoNavItem;
 
     private SpinnerAdapter mSpinnerAdapter;
-    private OnNavigationListener mCallback;
+    private AdapterView.OnItemSelectedListener mNavItemSelectedListener;
 
     private Runnable mTabSelector;
 
@@ -138,18 +136,6 @@
 
     Window.Callback mWindowCallback;
 
-    private final AdapterView.OnItemSelectedListener mNavItemSelectedListener =
-            new AdapterView.OnItemSelectedListener() {
-        public void onItemSelected(AdapterView parent, View view, int position, long id) {
-            if (mCallback != null) {
-                mCallback.onNavigationItemSelected(position, id);
-            }
-        }
-        public void onNothingSelected(AdapterView parent) {
-            // Do nothing
-        }
-    };
-
     private final OnClickListener mExpandedActionViewUpListener = new OnClickListener() {
         @Override
         public void onClick(View v) {
@@ -178,8 +164,6 @@
         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.ActionBar,
                 com.android.internal.R.attr.actionBarStyle, 0);
 
-        ApplicationInfo appInfo = context.getApplicationInfo();
-        PackageManager pm = context.getPackageManager();
         mNavigationMode = a.getInt(R.styleable.ActionBar_navigationMode,
                 ActionBar.NAVIGATION_MODE_STANDARD);
         mTitle = a.getText(R.styleable.ActionBar_title);
@@ -260,7 +244,7 @@
         }
 
         if (mHomeDescriptionRes != 0) {
-            setHomeActionContentDescription(mHomeDescriptionRes);
+            setNavigationContentDescription(mHomeDescriptionRes);
         }
 
         if (mTabScrollView != null && mIncludeTabs) {
@@ -313,7 +297,7 @@
     }
 
     @Override
-    public void setSplitActionBar(boolean splitActionBar) {
+    public void setSplitToolbar(boolean splitActionBar) {
         if (mSplitActionBar != splitActionBar) {
             if (mMenuView != null) {
                 final ViewGroup oldParent = (ViewGroup) mMenuView.getParent();
@@ -349,18 +333,26 @@
                     mActionMenuPresenter.setItemLimit(Integer.MAX_VALUE);
                 }
             }
-            super.setSplitActionBar(splitActionBar);
+            super.setSplitToolbar(splitActionBar);
         }
     }
 
-    public boolean isSplitActionBar() {
+    public boolean isSplit() {
         return mSplitActionBar;
     }
 
+    public boolean canSplit() {
+        return true;
+    }
+
     public boolean hasEmbeddedTabs() {
         return mIncludeTabs;
     }
 
+    public void setEmbeddedTabView(View view) {
+        setEmbeddedTabView((ScrollingTabContainerView) view);
+    }
+
     public void setEmbeddedTabView(ScrollingTabContainerView tabs) {
         if (mTabScrollView != null) {
             removeView(mTabScrollView);
@@ -376,10 +368,6 @@
         }
     }
 
-    public void setCallback(OnNavigationListener callback) {
-        mCallback = callback;
-    }
-
     public void setMenuPrepared() {
         mMenuPrepared = true;
     }
@@ -473,7 +461,7 @@
         }
     }
 
-    public void setCustomNavigationView(View view) {
+    public void setCustomView(View view) {
         final boolean showCustom = (mDisplayOptions & ActionBar.DISPLAY_SHOW_CUSTOM) != 0;
         if (showCustom) {
             ActionBarTransition.beginDelayedTransition(this);
@@ -765,15 +753,16 @@
         }
     }
 
-    public void setDropdownAdapter(SpinnerAdapter adapter) {
+    public void setDropdownParams(SpinnerAdapter adapter, AdapterView.OnItemSelectedListener l) {
         mSpinnerAdapter = adapter;
+        mNavItemSelectedListener = l;
         if (mSpinner != null) {
             mSpinner.setAdapter(adapter);
         }
     }
 
-    public SpinnerAdapter getDropdownAdapter() {
-        return mSpinnerAdapter;
+    public int getDropdownItemCount() {
+        return mSpinnerAdapter != null ? mSpinnerAdapter.getCount() : 0;
     }
 
     public void setDropdownSelectedPosition(int position) {
@@ -784,7 +773,7 @@
         return mSpinner.getSelectedItemPosition();
     }
 
-    public View getCustomNavigationView() {
+    public View getCustomView() {
         return mCustomNavView;
     }
 
@@ -797,6 +786,11 @@
     }
 
     @Override
+    public ViewGroup getViewGroup() {
+        return this;
+    }
+
+    @Override
     protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
         // Used by custom nav views if they don't supply layout params. Everything else
         // added to an ActionBarView should have them already.
@@ -860,12 +854,8 @@
         mContextView = view;
     }
 
-    public void setCollapsable(boolean collapsable) {
-        mIsCollapsable = collapsable;
-    }
-
-    public boolean isCollapsed() {
-        return mIsCollapsed;
+    public void setCollapsible(boolean collapsible) {
+        mIsCollapsible = collapsible;
     }
 
     /**
@@ -893,7 +883,7 @@
     @Override
     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
         final int childCount = getChildCount();
-        if (mIsCollapsable) {
+        if (mIsCollapsible) {
             int visibleChildren = 0;
             for (int i = 0; i < childCount; i++) {
                 final View child = getChildAt(i);
@@ -915,11 +905,9 @@
             if (visibleChildren == 0) {
                 // No size for an empty action bar when collapsable.
                 setMeasuredDimension(0, 0);
-                mIsCollapsed = true;
                 return;
             }
         }
-        mIsCollapsed = false;
 
         int widthMode = MeasureSpec.getMode(widthMeasureSpec);
         if (widthMode != MeasureSpec.EXACTLY) {
@@ -1323,20 +1311,20 @@
         }
     }
 
-    public void setHomeAsUpIndicator(Drawable indicator) {
+    public void setNavigationIcon(Drawable indicator) {
         mHomeLayout.setUpIndicator(indicator);
     }
 
-    public void setHomeAsUpIndicator(int resId) {
+    public void setNavigationIcon(int resId) {
         mHomeLayout.setUpIndicator(resId);
     }
 
-    public void setHomeActionContentDescription(CharSequence description) {
+    public void setNavigationContentDescription(CharSequence description) {
         mHomeDescription = description;
         updateHomeAccessibility(mUpGoerFive.isEnabled());
     }
 
-    public void setHomeActionContentDescription(int resId) {
+    public void setNavigationContentDescription(int resId) {
         mHomeDescriptionRes = resId;
         mHomeDescription = resId != 0 ? getResources().getText(resId) : null;
         updateHomeAccessibility(mUpGoerFive.isEnabled());
diff --git a/core/java/com/android/internal/widget/DecorToolbar.java b/core/java/com/android/internal/widget/DecorToolbar.java
new file mode 100644
index 0000000..ee6988e
--- /dev/null
+++ b/core/java/com/android/internal/widget/DecorToolbar.java
@@ -0,0 +1,94 @@
+/*
+ * 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.widget;
+
+import android.content.Context;
+import android.graphics.drawable.Drawable;
+import android.os.Parcelable;
+import android.util.SparseArray;
+import android.view.Menu;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.AdapterView;
+import android.widget.SpinnerAdapter;
+import com.android.internal.view.menu.MenuPresenter;
+
+/**
+ * Common interface for a toolbar that sits as part of the window decor.
+ * Layouts that control window decor use this as a point of interaction with different
+ * bar implementations.
+ *
+ * @hide
+ */
+public interface DecorToolbar {
+    ViewGroup getViewGroup();
+    Context getContext();
+    boolean isSplit();
+    boolean hasExpandedActionView();
+    void collapseActionView();
+    void setWindowCallback(Window.Callback cb);
+    void setWindowTitle(CharSequence title);
+    CharSequence getTitle();
+    void setTitle(CharSequence title);
+    CharSequence getSubtitle();
+    void setSubtitle(CharSequence subtitle);
+    void initProgress();
+    void initIndeterminateProgress();
+    boolean canSplit();
+    void setSplitView(ViewGroup splitView);
+    void setSplitToolbar(boolean split);
+    void setSplitWhenNarrow(boolean splitWhenNarrow);
+    boolean hasIcon();
+    boolean hasLogo();
+    void setIcon(int resId);
+    void setIcon(Drawable d);
+    void setLogo(int resId);
+    void setLogo(Drawable d);
+    boolean canShowOverflowMenu();
+    boolean isOverflowMenuShowing();
+    boolean isOverflowMenuShowPending();
+    boolean showOverflowMenu();
+    boolean hideOverflowMenu();
+    void setMenuPrepared();
+    void setMenu(Menu menu, MenuPresenter.Callback cb);
+    void dismissPopupMenus();
+
+    int getDisplayOptions();
+    void setDisplayOptions(int opts);
+    void setEmbeddedTabView(View tabView);
+    boolean hasEmbeddedTabs();
+    boolean isTitleTruncated();
+    void setCollapsible(boolean collapsible);
+    void setHomeButtonEnabled(boolean enable);
+    int getNavigationMode();
+    void setNavigationMode(int mode);
+    void setDropdownParams(SpinnerAdapter adapter, AdapterView.OnItemSelectedListener listener);
+    void setDropdownSelectedPosition(int position);
+    int getDropdownSelectedPosition();
+    int getDropdownItemCount();
+    void setCustomView(View view);
+    View getCustomView();
+    void animateToVisibility(int visibility);
+    void setNavigationIcon(Drawable icon);
+    void setNavigationIcon(int resId);
+    void setNavigationContentDescription(CharSequence description);
+    void setNavigationContentDescription(int resId);
+    void saveHierarchyState(SparseArray<Parcelable> toolbarStates);
+    void restoreHierarchyState(SparseArray<Parcelable> toolbarStates);
+}
diff --git a/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
new file mode 100644
index 0000000..f90aaea
--- /dev/null
+++ b/core/java/com/android/internal/widget/ToolbarWidgetWrapper.java
@@ -0,0 +1,526 @@
+/*
+ * 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.widget;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.app.ActionBar;
+import android.content.Context;
+import android.content.res.TypedArray;
+import android.graphics.drawable.Drawable;
+import android.os.Parcelable;
+import android.util.Log;
+import android.util.SparseArray;
+import android.view.LayoutInflater;
+import android.view.Menu;
+import android.view.View;
+import android.view.ViewGroup;
+import android.view.Window;
+import android.widget.ActionMenuPresenter;
+import android.widget.AdapterView;
+import android.widget.Spinner;
+import android.widget.SpinnerAdapter;
+import android.widget.Toolbar;
+import com.android.internal.R;
+import com.android.internal.view.menu.ActionMenuItem;
+import com.android.internal.view.menu.MenuBuilder;
+import com.android.internal.view.menu.MenuPresenter;
+
+/**
+ * Internal class used to interact with the Toolbar widget without
+ * exposing interface methods to the public API.
+ *
+ * <p>ToolbarWidgetWrapper manages the differences between Toolbar and ActionBarView
+ * so that either variant acting as a
+ * {@link com.android.internal.app.WindowDecorActionBar WindowDecorActionBar} can behave
+ * in the same way.</p>
+ *
+ * @hide
+ */
+public class ToolbarWidgetWrapper implements DecorToolbar {
+    private static final String TAG = "ToolbarWidgetWrapper";
+
+    private static final int AFFECTS_LOGO_MASK =
+            ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_USE_LOGO;
+
+    private Toolbar mToolbar;
+
+    private int mDisplayOpts;
+    private View mTabView;
+    private Spinner mSpinner;
+    private View mCustomView;
+
+    private Drawable mIcon;
+    private Drawable mLogo;
+    private Drawable mNavIcon;
+
+    private boolean mTitleSet;
+    private CharSequence mTitle;
+    private CharSequence mSubtitle;
+
+    private Window.Callback mWindowCallback;
+    private boolean mMenuPrepared;
+    private ActionMenuPresenter mActionMenuPresenter;
+
+    public ToolbarWidgetWrapper(Toolbar toolbar) {
+        mToolbar = toolbar;
+
+        final TypedArray a = toolbar.getContext().obtainStyledAttributes(null,
+                R.styleable.ActionBar, R.attr.actionBarStyle, 0);
+
+        final CharSequence title = a.getText(R.styleable.ActionBar_title);
+        if (title != null) {
+            setTitle(title);
+        }
+
+        final CharSequence subtitle = a.getText(R.styleable.ActionBar_subtitle);
+        if (subtitle != null) {
+            setSubtitle(subtitle);
+        }
+
+        final Drawable logo = a.getDrawable(R.styleable.ActionBar_logo);
+        if (logo != null) {
+            setLogo(logo);
+        }
+
+        final Drawable icon = a.getDrawable(R.styleable.ActionBar_icon);
+        if (icon != null) {
+            setIcon(icon);
+        }
+
+        final Drawable navIcon = a.getDrawable(R.styleable.ActionBar_homeAsUpIndicator);
+        if (navIcon != null) {
+            setNavigationIcon(navIcon);
+        }
+
+        setDisplayOptions(a.getInt(R.styleable.ActionBar_displayOptions, 0));
+
+        final int customNavId = a.getResourceId(R.styleable.ActionBar_customNavigationLayout, 0);
+        if (customNavId != 0) {
+            setCustomView(LayoutInflater.from(mToolbar.getContext()).inflate(customNavId,
+                    mToolbar, false));
+            setDisplayOptions(mDisplayOpts | ActionBar.DISPLAY_SHOW_CUSTOM);
+        }
+
+        final int height = a.getLayoutDimension(R.styleable.ActionBar_height, 0);
+        if (height > 0) {
+            final ViewGroup.LayoutParams lp = mToolbar.getLayoutParams();
+            lp.height = height;
+            mToolbar.setLayoutParams(lp);
+        }
+
+        final int contentInsetStart = a.getDimensionPixelOffset(
+                R.styleable.ActionBar_contentInsetStart, 0);
+        final int contentInsetEnd = a.getDimensionPixelOffset(
+                R.styleable.ActionBar_contentInsetEnd, 0);
+        if (contentInsetStart > 0 || contentInsetEnd > 0) {
+            mToolbar.setContentInsetsRelative(contentInsetStart, contentInsetEnd);
+        }
+
+        a.recycle();
+
+        mToolbar.setNavigationOnClickListener(new View.OnClickListener() {
+            final ActionMenuItem mNavItem = new ActionMenuItem(mToolbar.getContext(),
+                    0, android.R.id.home, 0, 0, mTitle);
+            @Override
+            public void onClick(View v) {
+                if (mWindowCallback != null && mMenuPrepared) {
+                    mWindowCallback.onMenuItemSelected(Window.FEATURE_OPTIONS_PANEL, mNavItem);
+                }
+            }
+        });
+    }
+
+    @Override
+    public ViewGroup getViewGroup() {
+        return mToolbar;
+    }
+
+    @Override
+    public Context getContext() {
+        return mToolbar.getContext();
+    }
+
+    @Override
+    public boolean isSplit() {
+        return false;
+    }
+
+    @Override
+    public boolean hasExpandedActionView() {
+        return mToolbar.hasExpandedActionView();
+    }
+
+    @Override
+    public void collapseActionView() {
+        mToolbar.collapseActionView();
+    }
+
+    @Override
+    public void setWindowCallback(Window.Callback cb) {
+        mWindowCallback = cb;
+    }
+
+    @Override
+    public void setWindowTitle(CharSequence title) {
+        // "Real" title always trumps window title.
+        if (!mTitleSet) {
+            setTitleInt(title);
+        }
+    }
+
+    @Override
+    public CharSequence getTitle() {
+        return mToolbar.getTitle();
+    }
+
+    @Override
+    public void setTitle(CharSequence title) {
+        mTitleSet = true;
+        setTitleInt(title);
+    }
+
+    private void setTitleInt(CharSequence title) {
+        mTitle = title;
+        if ((mDisplayOpts & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
+            mToolbar.setTitle(title);
+        }
+    }
+
+    @Override
+    public CharSequence getSubtitle() {
+        return mToolbar.getSubtitle();
+    }
+
+    @Override
+    public void setSubtitle(CharSequence subtitle) {
+        mSubtitle = subtitle;
+        if ((mDisplayOpts & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
+            mToolbar.setSubtitle(subtitle);
+        }
+    }
+
+    @Override
+    public void initProgress() {
+        Log.i(TAG, "Progress display unsupported");
+    }
+
+    @Override
+    public void initIndeterminateProgress() {
+        Log.i(TAG, "Progress display unsupported");
+    }
+
+    @Override
+    public boolean canSplit() {
+        return false;
+    }
+
+    @Override
+    public void setSplitView(ViewGroup splitView) {
+    }
+
+    @Override
+    public void setSplitToolbar(boolean split) {
+        if (split) {
+            throw new UnsupportedOperationException("Cannot split an android.widget.Toolbar");
+        }
+    }
+
+    @Override
+    public void setSplitWhenNarrow(boolean splitWhenNarrow) {
+        // Ignore.
+    }
+
+    @Override
+    public boolean hasIcon() {
+        return mIcon != null;
+    }
+
+    @Override
+    public boolean hasLogo() {
+        return mLogo != null;
+    }
+
+    @Override
+    public void setIcon(int resId) {
+        setIcon(resId != 0 ? getContext().getDrawable(resId) : null);
+    }
+
+    @Override
+    public void setIcon(Drawable d) {
+        mIcon = d;
+        updateToolbarLogo();
+    }
+
+    @Override
+    public void setLogo(int resId) {
+        setLogo(resId != 0 ? getContext().getDrawable(resId) : null);
+    }
+
+    @Override
+    public void setLogo(Drawable d) {
+        mLogo = d;
+        updateToolbarLogo();
+    }
+
+    private void updateToolbarLogo() {
+        Drawable logo = null;
+        if ((mDisplayOpts & ActionBar.DISPLAY_SHOW_HOME) != 0) {
+            if ((mDisplayOpts & ActionBar.DISPLAY_USE_LOGO) != 0) {
+                logo = mLogo != null ? mLogo : mIcon;
+            } else {
+                logo = mIcon;
+            }
+        }
+        mToolbar.setLogo(logo);
+    }
+
+    @Override
+    public boolean canShowOverflowMenu() {
+        return mToolbar.canShowOverflowMenu();
+    }
+
+    @Override
+    public boolean isOverflowMenuShowing() {
+        return mToolbar.isOverflowMenuShowing();
+    }
+
+    @Override
+    public boolean isOverflowMenuShowPending() {
+        return mToolbar.isOverflowMenuShowPending();
+    }
+
+    @Override
+    public boolean showOverflowMenu() {
+        return mToolbar.showOverflowMenu();
+    }
+
+    @Override
+    public boolean hideOverflowMenu() {
+        return mToolbar.hideOverflowMenu();
+    }
+
+    @Override
+    public void setMenuPrepared() {
+        mMenuPrepared = true;
+    }
+
+    @Override
+    public void setMenu(Menu menu, MenuPresenter.Callback cb) {
+        if (mActionMenuPresenter == null) {
+            mActionMenuPresenter = new ActionMenuPresenter(mToolbar.getContext());
+            mActionMenuPresenter.setId(com.android.internal.R.id.action_menu_presenter);
+        }
+        mActionMenuPresenter.setCallback(cb);
+        mToolbar.setMenu((MenuBuilder) menu, mActionMenuPresenter);
+    }
+
+    @Override
+    public void dismissPopupMenus() {
+        mToolbar.dismissPopupMenus();
+    }
+
+    @Override
+    public int getDisplayOptions() {
+        return mDisplayOpts;
+    }
+
+    @Override
+    public void setDisplayOptions(int newOpts) {
+        final int oldOpts = mDisplayOpts;
+        final int changed = oldOpts ^ newOpts;
+        mDisplayOpts = newOpts;
+        if (changed != 0) {
+            if ((changed & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
+                if ((newOpts & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
+                    mToolbar.setNavigationIcon(mNavIcon);
+                } else {
+                    mToolbar.setNavigationIcon(null);
+                }
+            }
+
+            if ((changed & AFFECTS_LOGO_MASK) != 0) {
+                updateToolbarLogo();
+            }
+
+            if ((changed & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
+                if ((newOpts & ActionBar.DISPLAY_SHOW_TITLE) != 0) {
+                    mToolbar.setTitle(mTitle);
+                    mToolbar.setSubtitle(mSubtitle);
+                } else {
+                    mToolbar.setTitle(null);
+                    mToolbar.setSubtitle(null);
+                }
+            }
+
+            if ((changed & ActionBar.DISPLAY_SHOW_CUSTOM) != 0 && mCustomView != null) {
+                if ((newOpts & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
+                    mToolbar.addView(mCustomView);
+                } else {
+                    mToolbar.removeView(mCustomView);
+                }
+            }
+        }
+    }
+
+    @Override
+    public void setEmbeddedTabView(View tabView) {
+        mTabView = tabView;
+    }
+
+    @Override
+    public boolean hasEmbeddedTabs() {
+        return mTabView != null;
+    }
+
+    @Override
+    public boolean isTitleTruncated() {
+        return mToolbar.isTitleTruncated();
+    }
+
+    @Override
+    public void setCollapsible(boolean collapsible) {
+        // Ignore
+    }
+
+    @Override
+    public void setHomeButtonEnabled(boolean enable) {
+        // Ignore
+    }
+
+    @Override
+    public int getNavigationMode() {
+        return 0;
+    }
+
+    @Override
+    public void setNavigationMode(int mode) {
+        if (mode != ActionBar.NAVIGATION_MODE_STANDARD) {
+            throw new IllegalArgumentException(
+                    "Navigation modes not supported in this configuration");
+        }
+    }
+
+    @Override
+    public void setDropdownParams(SpinnerAdapter adapter,
+            AdapterView.OnItemSelectedListener listener) {
+        if (mSpinner == null) {
+            mSpinner = new Spinner(getContext());
+        }
+        mSpinner.setAdapter(adapter);
+        mSpinner.setOnItemSelectedListener(listener);
+    }
+
+    @Override
+    public void setDropdownSelectedPosition(int position) {
+        if (mSpinner == null) {
+            throw new IllegalStateException(
+                    "Can't set dropdown selected position without an adapter");
+        }
+        mSpinner.setSelection(position);
+    }
+
+    @Override
+    public int getDropdownSelectedPosition() {
+        return mSpinner != null ? mSpinner.getSelectedItemPosition() : 0;
+    }
+
+    @Override
+    public int getDropdownItemCount() {
+        return mSpinner != null ? mSpinner.getCount() : 0;
+    }
+
+    @Override
+    public void setCustomView(View view) {
+        if (mCustomView != null && (mDisplayOpts & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
+            mToolbar.removeView(mCustomView);
+        }
+        mCustomView = view;
+        if (view != null && (mDisplayOpts & ActionBar.DISPLAY_SHOW_CUSTOM) != 0) {
+            mToolbar.addView(mCustomView);
+        }
+    }
+
+    @Override
+    public View getCustomView() {
+        return mCustomView;
+    }
+
+    @Override
+    public void animateToVisibility(int visibility) {
+        if (visibility == View.GONE) {
+            mToolbar.animate().translationY(mToolbar.getHeight()).alpha(0)
+                    .setListener(new AnimatorListenerAdapter() {
+                        private boolean mCanceled = false;
+                        @Override
+                        public void onAnimationEnd(Animator animation) {
+                            if (!mCanceled) {
+                                mToolbar.setVisibility(View.GONE);
+                            }
+                        }
+
+                        @Override
+                        public void onAnimationCancel(Animator animation) {
+                            mCanceled = true;
+                        }
+                    });
+        } else if (visibility == View.VISIBLE) {
+            mToolbar.animate().translationY(0).alpha(1)
+                    .setListener(new AnimatorListenerAdapter() {
+                        @Override
+                        public void onAnimationStart(Animator animation) {
+                            mToolbar.setVisibility(View.VISIBLE);
+                        }
+                    });
+        }
+    }
+
+    @Override
+    public void setNavigationIcon(Drawable icon) {
+        mNavIcon = icon;
+        if ((mDisplayOpts & ActionBar.DISPLAY_HOME_AS_UP) != 0) {
+            mToolbar.setNavigationIcon(icon);
+        }
+    }
+
+    @Override
+    public void setNavigationIcon(int resId) {
+        setNavigationIcon(mToolbar.getContext().getDrawable(resId));
+    }
+
+    @Override
+    public void setNavigationContentDescription(CharSequence description) {
+        mToolbar.setNavigationContentDescription(description);
+    }
+
+    @Override
+    public void setNavigationContentDescription(int resId) {
+        mToolbar.setNavigationContentDescription(resId);
+    }
+
+    @Override
+    public void saveHierarchyState(SparseArray<Parcelable> toolbarStates) {
+        mToolbar.saveHierarchyState(toolbarStates);
+    }
+
+    @Override
+    public void restoreHierarchyState(SparseArray<Parcelable> toolbarStates) {
+        mToolbar.restoreHierarchyState(toolbarStates);
+    }
+
+}
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index 0c7eefa..e069876 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -789,7 +789,7 @@
     }
 
     // libart tolerates libdvm flags, but not vice versa, so only pass some options if libart.
-    property_get("persist.sys.dalvik.vm.lib.1", dalvikVmLibBuf, "libdvm.so");
+    property_get("persist.sys.dalvik.vm.lib.2", dalvikVmLibBuf, "libart.so");
     bool libart = (strncmp(dalvikVmLibBuf, "libart", 6) == 0);
 
     if (libart) {
diff --git a/core/res/res/layout/screen_toolbar.xml b/core/res/res/layout/screen_toolbar.xml
new file mode 100644
index 0000000..290c7da
--- /dev/null
+++ b/core/res/res/layout/screen_toolbar.xml
@@ -0,0 +1,51 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+
+<!--
+This is an optimized layout for a screen with a toolbar enabled.
+-->
+
+<com.android.internal.widget.ActionBarOverlayLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/decor_content_parent"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:splitMotionEvents="false"
+    android:theme="?attr/actionBarTheme">
+    <FrameLayout android:id="@android:id/content"
+                 android:layout_width="match_parent"
+                 android:layout_height="match_parent" />
+    <com.android.internal.widget.ActionBarContainer
+        android:id="@+id/action_bar_container"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_alignParentTop="true"
+        style="?attr/actionBarStyle"
+        android:viewName="android:action_bar"
+        android:gravity="top">
+        <Toolbar
+            android:id="@+id/action_bar"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            style="?attr/toolbarStyle" />
+        <com.android.internal.widget.ActionBarContextView
+            android:id="@+id/action_context_bar"
+            android:layout_width="match_parent"
+            android:layout_height="wrap_content"
+            android:visibility="gone"
+            style="?attr/actionModeStyle" />
+    </com.android.internal.widget.ActionBarContainer>
+</com.android.internal.widget.ActionBarOverlayLayout>
diff --git a/core/res/res/values/attrs.xml b/core/res/res/values/attrs.xml
index c05dfca..5fec907 100644
--- a/core/res/res/values/attrs.xml
+++ b/core/res/res/values/attrs.xml
@@ -493,6 +493,9 @@
              {@link android.view.Window#setAllowExitTransitionOverlap(boolean)}. -->
         <attr name="windowAllowExitTransitionOverlap" format="boolean"/>
 
+        <!-- Internal layout used internally for window decor -->
+        <attr name="windowActionBarFullscreenDecorLayout" format="reference" />
+
         <!-- ============ -->
         <!-- Alert Dialog styles -->
         <!-- ============ -->
@@ -685,6 +688,7 @@
         <!-- Default ActivityChooserView style. -->
         <attr name="activityChooserViewStyle" format="reference" />
 
+        <!-- Default Toolbar style. -->
         <attr name="toolbarStyle" format="reference" />
 
         <!-- Fast scroller styles -->
@@ -1713,6 +1717,7 @@
         <attr name="windowSwipeToDismiss" />
         <attr name="windowContentTransitions" />
         <attr name="windowContentTransitionManager" />
+        <attr name="windowActionBarFullscreenDecorLayout" />
 
         <!-- The minimum width the window is allowed to be, along the major
              axis of the screen.  That is, when in landscape.  Can be either
@@ -6398,11 +6403,17 @@
         <attr name="indeterminateProgressStyle" format="reference" />
         <!-- Specifies the horizontal padding on either end for an embedded progress bar. -->
         <attr name="progressBarPadding" format="dimension" />
+        <!-- Up navigation glyph -->
+        <attr name="homeAsUpIndicator" />
         <!-- Specifies padding that should be applied to the left and right sides of
              system-provided items in the bar. -->
         <attr name="itemPadding" format="dimension" />
         <!-- Set true to hide the action bar on a vertical nested scroll of content. -->
         <attr name="hideOnContentScroll" format="boolean" />
+        <attr name="contentInsetStart" format="dimension" />
+        <attr name="contentInsetEnd" format="dimension" />
+        <attr name="contentInsetLeft" format="dimension" />
+        <attr name="contentInsetRight" format="dimension" />
     </declare-styleable>
 
     <declare-styleable name="ActionMode">
@@ -6653,10 +6664,19 @@
         <attr name="titleMarginEnd" format="dimension" />
         <attr name="titleMarginTop" format="dimension" />
         <attr name="titleMarginBottom" format="dimension" />
-        <attr name="contentInsetStart" format="dimension" />
-        <attr name="contentInsetEnd" format="dimension" />
-        <attr name="contentInsetLeft" format="dimension" />
-        <attr name="contentInsetRight" format="dimension" />
+        <attr name="contentInsetStart" />
+        <attr name="contentInsetEnd" />
+        <attr name="contentInsetLeft" />
+        <attr name="contentInsetRight" />
+        <attr name="maxButtonHeight" format="dimension" />
+        <attr name="navigationButtonStyle" format="reference" />
+        <attr name="buttonGravity">
+            <!-- Push object to the top of its container, not changing its size. -->
+            <flag name="top" value="0x30" />
+            <!-- Push object to the bottom of its container, not changing its size. -->
+            <flag name="bottom" value="0x50" />
+        </attr>
+        <attr name="collapseIcon" format="reference" />
     </declare-styleable>
 
     <declare-styleable name="Toolbar_LayoutParams">
diff --git a/core/res/res/values/styles.xml b/core/res/res/values/styles.xml
index f6cd9e8..fc6110d 100644
--- a/core/res/res/values/styles.xml
+++ b/core/res/res/values/styles.xml
@@ -1197,6 +1197,16 @@
         <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>
+        <item name="android:maxButtonHeight">56dp</item>
+        <item name="android:buttonGravity">top</item>
+        <item name="android:navigationButtonStyle">@android:style/Widget.Toolbar.Button.Navigation</item>
+        <item name="android:collapseIcon">?android:attr/homeAsUpIndicator</item>
+    </style>
+
+    <style name="Widget.Toolbar.Button.Navigation" parent="@android:style/Widget">
+        <item name="android:background">?android:attr/selectableItemBackground</item>
+        <item name="android:minWidth">56dp</item>
+        <item name="android:scaleType">center</item>
     </style>
 
     <style name="TextAppearance.Widget.ActionBar.Title"
@@ -2394,7 +2404,6 @@
         <item name="android:background">@android:drawable/ab_transparent_light_holo</item>
         <item name="android:backgroundStacked">@android:drawable/ab_stacked_transparent_light_holo</item>
         <item name="android:backgroundSplit">@android:drawable/ab_bottom_transparent_light_holo</item>
-        <item name="android:homeAsUpIndicator">@android:drawable/ic_ab_back_holo_light</item>
         <item name="android:progressBarStyle">@android:style/Widget.Holo.Light.ProgressBar.Horizontal</item>
         <item name="android:indeterminateProgressStyle">@android:style/Widget.Holo.Light.ProgressBar</item>
     </style>
diff --git a/core/res/res/values/styles_quantum.xml b/core/res/res/values/styles_quantum.xml
index 2e7a5b1..ea32681 100644
--- a/core/res/res/values/styles_quantum.xml
+++ b/core/res/res/values/styles_quantum.xml
@@ -773,7 +773,7 @@
         <item name="background">@null</item>
         <item name="backgroundStacked">@null</item>
         <item name="backgroundSplit">@null</item>
-        <item name="displayOptions">useLogo|showHome|showTitle</item>
+        <item name="displayOptions">showTitle</item>
         <item name="divider">?attr/dividerVertical</item>
         <item name="titleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Title</item>
         <item name="subtitleTextStyle">@style/TextAppearance.Quantum.Widget.ActionBar.Subtitle</item>
@@ -783,6 +783,7 @@
         <item name="itemPadding">8dip</item>
         <item name="homeLayout">@layout/action_bar_home_quantum</item>
         <item name="gravity">center_vertical</item>
+        <item name="contentInsetStart">56dp</item>
     </style>
 
     <style name="Widget.Quantum.ActionBar.Solid">
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 69f73e5..4109d03 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -1862,6 +1862,7 @@
   <java-symbol type="attr" name="toolbarStyle" />
   <java-symbol type="attr" name="titleTextAppearance" />
   <java-symbol type="attr" name="subtitleTextAppearance" />
+  <java-symbol type="attr" name="windowActionBarFullscreenDecorLayout" />
   <java-symbol type="drawable" name="ic_lock_bugreport" />
   <java-symbol type="id" name="icon_frame" />
   <java-symbol type="style" name="Animation.VolumePanel" />
diff --git a/core/res/res/values/themes.xml b/core/res/res/values/themes.xml
index aaab949..41f4ff8 100644
--- a/core/res/res/values/themes.xml
+++ b/core/res/res/values/themes.xml
@@ -192,6 +192,7 @@
         <item name="windowDrawsSystemBarBackgrounds">false</item>
         <item name="statusBarColor">@android:color/black</item>
         <item name="navigationBarColor">@android:color/black</item>
+        <item name="windowActionBarFullscreenDecorLayout">@layout/screen_action_bar</item>
 
         <!-- Define these here; ContextThemeWrappers around themes that define them should
              always clear these values. -->
diff --git a/core/res/res/values/themes_quantum.xml b/core/res/res/values/themes_quantum.xml
index bb787bb..484c694 100644
--- a/core/res/res/values/themes_quantum.xml
+++ b/core/res/res/values/themes_quantum.xml
@@ -162,6 +162,7 @@
         <item name="windowActionBar">true</item>
         <item name="windowActionModeOverlay">false</item>
         <item name="windowDrawsSystemBarBackgrounds">true</item>
+        <item name="windowActionBarFullscreenDecorLayout">@layout/screen_toolbar</item>
         <item name="statusBarColor">?attr/colorPrimaryDark</item>
         <item name="navigationBarColor">?attr/colorPrimaryDark</item>
 
@@ -505,6 +506,7 @@
         <item name="windowActionBar">true</item>
         <item name="windowActionModeOverlay">false</item>
         <item name="windowDrawsSystemBarBackgrounds">true</item>
+        <item name="windowActionBarFullscreenDecorLayout">@layout/screen_toolbar</item>
         <item name="statusBarColor">?attr/colorPrimaryDark</item>
         <item name="navigationBarColor">?attr/colorPrimaryDark</item>
 
diff --git a/media/java/android/media/AudioDevicePort.java b/media/java/android/media/AudioDevicePort.java
new file mode 100644
index 0000000..c088906
--- /dev/null
+++ b/media/java/android/media/AudioDevicePort.java
@@ -0,0 +1,85 @@
+/*
+ * 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.media;
+
+/**
+ * The AudioDevicePort is a specialized type of AudioPort
+ * describing an input (e.g microphone) or output device (e.g speaker)
+ * of the system.
+ * An AudioDevicePort is an AudioPort controlled by the audio HAL, almost always a physical
+ * device at the boundary of the audio system.
+ * In addition to base audio port attributes, the device descriptor contains:
+ * - the device type (e.g AudioManager.DEVICE_OUT_SPEAKER)
+ * - the device address (e.g MAC adddress for AD2P sink).
+ * @see AudioPort
+ * @hide
+ */
+
+public class AudioDevicePort extends AudioPort {
+
+    private final int mType;
+    private final String mAddress;
+
+    AudioDevicePort(AudioHandle handle, int[] samplingRates, int[] channelMasks,
+            int[] formats, AudioGain[] gains, int type, String address) {
+        super(handle,
+             (AudioManager.isInputDevice(type) == true)  ?
+                        AudioPort.ROLE_SOURCE : AudioPort.ROLE_SINK,
+             samplingRates, channelMasks, formats, gains);
+        mType = type;
+        mAddress = address;
+    }
+
+    /**
+     * Get the device type (e.g AudioManager.DEVICE_OUT_SPEAKER)
+     */
+    public int type() {
+        return mType;
+    }
+
+    /**
+     * Get the device address. Address format varies with the device type.
+     * - USB devices ({@link AudioManager#DEVICE_OUT_USB_DEVICE},
+     * {@link AudioManager#DEVICE_IN_USB_DEVICE}) use an address composed of the ALSA card number
+     * and device number: "card=2;device=1"
+     * - Bluetooth devices ({@link AudioManager#DEVICE_OUT_BLUETOOTH_SCO},
+     * {@link AudioManager#DEVICE_OUT_BLUETOOTH_SCO}, {@link AudioManager#DEVICE_OUT_BLUETOOTH_A2DP})
+     * use the MAC address of the bluetooth device in the form "00:11:22:AA:BB:CC" as reported by
+     * {@link BluetoothDevice#getAddress()}.
+     * - Deivces that do not have an address will indicate an empty string "".
+     */
+    public String address() {
+        return mAddress;
+    }
+
+    /**
+     * Build a specific configuration of this audio device port for use by methods
+     * like AudioManager.connectAudioPatch().
+     */
+    public AudioDevicePortConfig buildConfig(int samplingRate, int channelMask, int format,
+                                          AudioGainConfig gain) {
+        return new AudioDevicePortConfig(this, samplingRate, channelMask, format, gain);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || !(o instanceof AudioDevicePort)) {
+            return false;
+        }
+        return super.equals(o);
+    }
+}
diff --git a/media/java/android/media/AudioDevicePortConfig.java b/media/java/android/media/AudioDevicePortConfig.java
new file mode 100644
index 0000000..a381e10
--- /dev/null
+++ b/media/java/android/media/AudioDevicePortConfig.java
@@ -0,0 +1,41 @@
+/*
+ * 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.media;
+
+/**
+ * An AudioDevicePortConfig describes a possible configuration of an output or input device
+ * (speaker, headphone, microphone ...).
+ * It is used to specify a sink or source when creating a connection with
+ * AudioManager.connectAudioPatch().
+ * An AudioDevicePortConfig is obtained from AudioDevicePort.buildConfig().
+ * @hide
+ */
+
+public class AudioDevicePortConfig extends AudioPortConfig {
+    AudioDevicePortConfig(AudioDevicePort devicePort, int samplingRate, int channelMask,
+            int format, AudioGainConfig gain) {
+        super((AudioPort)devicePort, samplingRate, channelMask, format, gain);
+    }
+
+    /**
+     * Returns the audio device port this AudioDevicePortConfig is issued from.
+     */
+    public AudioDevicePort port() {
+        return (AudioDevicePort)mPort;
+    }
+}
+
diff --git a/media/java/android/media/AudioGain.java b/media/java/android/media/AudioGain.java
new file mode 100644
index 0000000..57709d5
--- /dev/null
+++ b/media/java/android/media/AudioGain.java
@@ -0,0 +1,159 @@
+/*
+ * 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.media;
+
+/**
+ * The AudioGain describes a gain controller. Gain controllers are exposed by
+ * audio ports when the gain is configurable at this port's input or output.
+ * Gain values are expressed in millibels.
+ * A gain controller has the following attributes:
+ * - mode: defines modes of operation or features
+ *    MODE_JOINT: all channel gains are controlled simultaneously
+ *    MODE_CHANNELS: each channel gain is controlled individually
+ *    MODE_RAMP: ramps can be applied when gain changes
+ * - channel mask: indicates for which channels the gain can be controlled
+ * - min value: minimum gain value in millibel
+ * - max value: maximum gain value in millibel
+ * - default value: gain value after reset in millibel
+ * - step value: granularity of gain control in millibel
+ * - min ramp duration: minimum ramp duration in milliseconds
+ * - max ramp duration: maximum ramp duration in milliseconds
+ *
+ * This object is always created by the framework and read only by applications.
+ * Applications get a list of AudioGainDescriptors from AudioPortDescriptor.gains() and can build a
+ * valid gain configuration from AudioGain.buildConfig()
+ * @hide
+ */
+public class AudioGain {
+
+    /**
+     * Bit of AudioGain.mode() field indicating that
+     * all channel gains are controlled simultaneously
+     */
+    public static final int MODE_JOINT = 1;
+    /**
+     * Bit of AudioGain.mode() field indicating that
+     * each channel gain is controlled individually
+     */
+    public static final int MODE_CHANNELS = 2;
+    /**
+     * Bit of AudioGain.mode() field indicating that
+     * ramps can be applied when gain changes. The type of ramp (linear, log etc...) is
+     * implementation specific.
+     */
+    public static final int MODE_RAMP = 4;
+
+    private final int mIndex;
+    private final int mMode;
+    private final int mChannelMask;
+    private final int mMinValue;
+    private final int mMaxValue;
+    private final int mDefaultValue;
+    private final int mStepValue;
+    private final int mRampDurationMinMs;
+    private final int mRampDurationMaxMs;
+
+    // The channel mask passed to the constructor is as specified in AudioFormat
+    // (e.g. AudioFormat.CHANNEL_OUT_STEREO)
+    AudioGain(int index, int mode, int channelMask,
+                        int minValue, int maxValue, int defaultValue, int stepValue,
+                        int rampDurationMinMs, int rampDurationMaxMs) {
+        mIndex = index;
+        mMode = mode;
+        mChannelMask = channelMask;
+        mMinValue = minValue;
+        mMaxValue = maxValue;
+        mDefaultValue = defaultValue;
+        mStepValue = stepValue;
+        mRampDurationMinMs = rampDurationMinMs;
+        mRampDurationMaxMs = rampDurationMaxMs;
+    }
+
+    /**
+     * Bit field indicating supported modes of operation
+     */
+    public int mode() {
+        return mMode;
+    }
+
+    /**
+     * Indicates for which channels the gain can be controlled
+     * (e.g. AudioFormat.CHANNEL_OUT_STEREO)
+     */
+    public int channelMask() {
+        return mChannelMask;
+    }
+
+    /**
+     * Minimum gain value in millibel
+     */
+    public int minValue() {
+        return mMinValue;
+    }
+
+    /**
+     * Maximum gain value in millibel
+     */
+    public int maxValue() {
+        return mMaxValue;
+    }
+
+    /**
+     * Default gain value in millibel
+     */
+    public int defaultValue() {
+        return mDefaultValue;
+    }
+
+    /**
+     * Granularity of gain control in millibel
+     */
+    public int stepValue() {
+        return mStepValue;
+    }
+
+    /**
+     * Minimum ramp duration in milliseconds
+     * 0 if MODE_RAMP not set
+     */
+    public int rampDurationMinMs() {
+        return mRampDurationMinMs;
+    }
+
+    /**
+     * Maximum ramp duration in milliseconds
+     * 0 if MODE_RAMP not set
+     */
+    public int rampDurationMaxMs() {
+        return mRampDurationMaxMs;
+    }
+
+    /**
+     * Build a valid gain configuration for this gain controller for use by
+     * AudioPortDescriptor.setGain()
+     * @param mode: desired mode of operation
+     * @param channelMask: channels of which the gain should be modified.
+     * @param values: gain values for each channels.
+     * @param rampDurationMs: ramp duration if mode MODE_RAMP is set.
+     * ignored if MODE_JOINT.
+     */
+    public AudioGainConfig buildConfig(int mode, int channelMask,
+                                       int[] values, int rampDurationMs) {
+        //TODO: check params here
+        return new AudioGainConfig(mIndex, this, mode, channelMask, values, rampDurationMs);
+    }
+}
diff --git a/media/java/android/media/AudioGainConfig.java b/media/java/android/media/AudioGainConfig.java
new file mode 100644
index 0000000..ea61679
--- /dev/null
+++ b/media/java/android/media/AudioGainConfig.java
@@ -0,0 +1,84 @@
+/*
+ * 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.media;
+
+/**
+ * The AudioGainConfig is used by APIs setting or getting values on a given gain
+ * controller. It contains a valid configuration (value, channels...) for a gain controller
+ * exposed by an audio port.
+ * @see AudioGain
+ * @see AudioPort
+ * @hide
+ */
+public class AudioGainConfig {
+    AudioGain mGain;
+    private final int mIndex;
+    private final int mMode;
+    private final int mChannelMask;
+    private final int mValues[];
+    private final int mRampDurationMs;
+
+    AudioGainConfig(int index, AudioGain gain, int mode, int channelMask,
+            int[] values, int rampDurationMs) {
+        mIndex = index;
+        mGain = gain;
+        mMode = mode;
+        mChannelMask = channelMask;
+        mValues = values;
+        mRampDurationMs = rampDurationMs;
+    }
+
+    /**
+     * get the index of the parent gain.
+     * frameworks use only.
+     */
+    int index() {
+        return mIndex;
+    }
+
+    /**
+     * Bit field indicating requested modes of operation. See {@link AudioGain#MODE_JOINT},
+     * {@link AudioGain#MODE_CHANNELS}, {@link AudioGain#MODE_RAMP}
+     */
+    public int mode() {
+        return mMode;
+    }
+
+    /**
+     * Indicates for which channels the gain is set.
+     * See {@link AudioFormat#CHANNEL_OUT_STEREO}, {@link AudioFormat#CHANNEL_OUT_MONO} ...
+     */
+    public int channelMask() {
+        return mChannelMask;
+    }
+
+    /**
+     * Gain values for each channel in the order of bits set in
+     * channelMask() from LSB to MSB
+     */
+    public int[] values() {
+        return mValues;
+    }
+
+    /**
+     * Ramp duration in milliseconds. N/A if mode() does not
+     * specify MODE_RAMP.
+     */
+    public int rampDurationMs() {
+        return mRampDurationMs;
+    }
+}
diff --git a/media/java/android/media/AudioHandle.java b/media/java/android/media/AudioHandle.java
new file mode 100644
index 0000000..b58e7a3
--- /dev/null
+++ b/media/java/android/media/AudioHandle.java
@@ -0,0 +1,49 @@
+/*
+ * 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.media;
+
+/**
+ * The AudioHandle is used by the audio framework implementation to
+ * uniquely identify a particular component of the routing topology
+ * (AudioPort or AudioPatch)
+ * It is not visible or used at the API.
+ */
+class AudioHandle {
+    private final int mId;
+
+    AudioHandle(int id) {
+        mId = id;
+    }
+
+    int id() {
+        return mId;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || !(o instanceof AudioHandle)) {
+            return false;
+        }
+        AudioHandle ah = (AudioHandle)o;
+        return mId == ah.id();
+    }
+
+    @Override
+    public int hashCode() {
+        return mId;
+    }
+}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index 9803161..f4affa0 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -39,6 +39,7 @@
 import android.view.KeyEvent;
 
 import java.util.HashMap;
+import java.util.ArrayList;
 
 /**
  * AudioManager provides access to volume and ringer mode control.
@@ -2966,4 +2967,151 @@
             Log.w(TAG, "Error disabling safe media volume", e);
         }
     }
+
+    /**
+     * Return codes for listAudioPorts(), createAudioPatch() ...
+     */
+
+    /** @hide
+     */
+    public static final int SUCCESS = AudioSystem.SUCCESS;
+    /** @hide
+     */
+    public static final int ERROR = AudioSystem.ERROR;
+    /** @hide
+     */
+    public static final int ERROR_BAD_VALUE = AudioSystem.BAD_VALUE;
+    /** @hide
+     */
+    public static final int ERROR_INVALID_OPERATION = AudioSystem.INVALID_OPERATION;
+    /** @hide
+     */
+    public static final int ERROR_PERMISSION_DENIED = AudioSystem.PERMISSION_DENIED;
+    /** @hide
+     */
+    public static final int ERROR_NO_INIT = AudioSystem.NO_INIT;
+    /** @hide
+     */
+    public static final int ERROR_DEAD_OBJECT = AudioSystem.DEAD_OBJECT;
+
+    /**
+     * Returns a list of descriptors for all audio ports managed by the audio framework.
+     * Audio ports are nodes in the audio framework or audio hardware that can be configured
+     * or connected and disconnected with createAudioPatch() or releaseAudioPatch().
+     * See AudioPort for a list of attributes of each audio port.
+     * @param ports An AudioPort ArrayList where the list will be returned.
+     * @hide
+     */
+    public int listAudioPorts(ArrayList<AudioPort> ports) {
+        return ERROR_INVALID_OPERATION;
+    }
+
+    /**
+     * Specialized version of listAudioPorts() listing only audio devices (AudioDevicePort)
+     * @see listAudioPorts(ArrayList<AudioPort>)
+     * @hide
+     */
+    public int listAudioDevicePorts(ArrayList<AudioPort> devices) {
+        return ERROR_INVALID_OPERATION;
+    }
+
+    /**
+     * Create a connection between two or more devices. The framework will reject the request if
+     * device types are not compatible or the implementation does not support the requested
+     * configuration.
+     * NOTE: current implementation is limited to one source and one sink per patch.
+     * @param patch AudioPatch array where the newly created patch will be returned.
+     *              As input, if patch[0] is not null, the specified patch will be replaced by the
+     *              new patch created. This avoids calling releaseAudioPatch() when modifying a
+     *              patch and allows the implementation to optimize transitions.
+     * @param sources List of source audio ports. All must be AudioPort.ROLE_SOURCE.
+     * @param sinks   List of sink audio ports. All must be AudioPort.ROLE_SINK.
+     *
+     * @return - {@link #SUCCESS} if connection is successful.
+     *         - {@link #ERROR_BAD_VALUE} if incompatible device types are passed.
+     *         - {@link #ERROR_INVALID_OPERATION} if the requested connection is not supported.
+     *         - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to create
+     *         a patch.
+     *         - {@link #ERROR_DEAD_OBJECT} if the server process is dead
+     *         - {@link #ERROR} if patch cannot be connected for any other reason.
+     *
+     *         patch[0] contains the newly created patch
+     * @hide
+     */
+    public int createAudioPatch(AudioPatch[] patch,
+                                 AudioPortConfig[] sources,
+                                 AudioPortConfig[] sinks) {
+        return ERROR_INVALID_OPERATION;
+    }
+
+    /**
+     * Releases an existing audio patch connection.
+     * @param patch The audio patch to disconnect.
+     * @return - {@link #SUCCESS} if disconnection is successful.
+     *         - {@link #ERROR_BAD_VALUE} if the specified patch does not exist.
+     *         - {@link #ERROR_PERMISSION_DENIED} if the client does not have permission to release
+     *         a patch.
+     *         - {@link #ERROR_DEAD_OBJECT} if the server process is dead
+     *         - {@link #ERROR} if patch cannot be released for any other reason.
+     * @hide
+     */
+    public int releaseAudioPatch(AudioPatch patch) {
+        return  ERROR_INVALID_OPERATION;
+    }
+
+    /**
+     * List all existing connections between audio ports.
+     * @param patches An AudioPatch array where the list will be returned.
+     * @hide
+     */
+    public int listAudioPatches(ArrayList<AudioPatch> patches) {
+        return ERROR_INVALID_OPERATION;
+    }
+
+    /**
+     * Set the gain on the specified AudioPort. The AudioGainConfig config is build by
+     * AudioGain.buildConfig()
+     * @hide
+     */
+    public int setAudioPortGain(AudioPort port, AudioGainConfig gain) {
+        return ERROR_INVALID_OPERATION;
+    }
+
+    /**
+     * Listener registered by client to be notified upon new audio port connections,
+     * disconnections or attributes update.
+     * @hide
+     */
+    public interface OnAudioPortUpdateListener {
+        /**
+         * Callback method called upon audio port list update.
+         * @param portList the updated list of audio ports
+         */
+        public void OnAudioPortListUpdate(AudioPort[] portList);
+
+        /**
+         * Callback method called upon audio patch list update.
+         * @param patchList the updated list of audio patches
+         */
+        public void OnAudioPatchListUpdate(AudioPatch[] patchList);
+
+        /**
+         * Callback method called when the mediaserver dies
+         */
+        public void OnServiceDied();
+    }
+
+    /**
+     * Register an audio port update listener.
+     * @hide
+     */
+    public void registerAudioPortUpdateListener(OnAudioPortUpdateListener l) {
+    }
+
+    /**
+     * Unregister an audio port update listener.
+     * @hide
+     */
+    public void unregisterAudioPortUpdateListener(OnAudioPortUpdateListener l) {
+    }
 }
diff --git a/media/java/android/media/AudioMixPort.java b/media/java/android/media/AudioMixPort.java
new file mode 100644
index 0000000..1500a43
--- /dev/null
+++ b/media/java/android/media/AudioMixPort.java
@@ -0,0 +1,51 @@
+/*
+ * 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.media;
+
+/**
+ * The AudioMixPort is a specialized type of AudioPort
+ * describing an audio mix or stream at an input or output stream of the audio
+ * framework.
+ * @see AudioPort
+ * @hide
+ */
+
+public class AudioMixPort extends AudioPort {
+
+    AudioMixPort(AudioHandle handle, int role, int[] samplingRates, int[] channelMasks,
+            int[] formats, AudioGain[] gains) {
+        super(handle, role, samplingRates, channelMasks, formats, gains);
+    }
+
+    /**
+     * Build a specific configuration of this audio mix port for use by methods
+     * like AudioManager.connectAudioPatch().
+     */
+    public AudioMixPortConfig buildConfig(int samplingRate, int channelMask, int format,
+                                       AudioGainConfig gain) {
+        return new AudioMixPortConfig(this, samplingRate, channelMask, format, gain);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || !(o instanceof AudioMixPort)) {
+            return false;
+        }
+        return super.equals(o);
+    }
+
+}
diff --git a/media/java/android/media/AudioMixPortConfig.java b/media/java/android/media/AudioMixPortConfig.java
new file mode 100644
index 0000000..8eb9ef46
--- /dev/null
+++ b/media/java/android/media/AudioMixPortConfig.java
@@ -0,0 +1,41 @@
+/*
+ * 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.media;
+
+/**
+ * An AudioMixPortConfig describes a possible configuration of an output or input mixer.
+ * It is used to specify a sink or source when creating a connection with
+ * AudioManager.connectAudioPatch().
+ * An AudioMixPortConfig is obtained from AudioMixPort.buildConfig().
+ * @hide
+ */
+
+public class AudioMixPortConfig extends AudioPortConfig {
+
+    AudioMixPortConfig(AudioMixPort mixPort, int samplingRate, int channelMask, int format,
+                AudioGainConfig gain) {
+        super((AudioPort)mixPort, samplingRate, channelMask, format, gain);
+    }
+
+    /**
+     * Returns the audio mix port this AudioMixPortConfig is issued from.
+     */
+    public AudioMixPort port() {
+        return (AudioMixPort)mPort;
+    }
+}
+
diff --git a/media/java/android/media/AudioPatch.java b/media/java/android/media/AudioPatch.java
new file mode 100644
index 0000000..72291f6
--- /dev/null
+++ b/media/java/android/media/AudioPatch.java
@@ -0,0 +1,55 @@
+/*
+ * 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.media;
+
+
+/**
+ * An AudioPatch describes a connection between audio sources and audio sinks.
+ * An audio source can be an output mix (playback AudioBus) or an input device (microphone).
+ * An audio sink can be an output device (speaker) or an input mix (capture AudioBus).
+ * An AudioPatch is created by AudioManager.connectAudioPatch() and released by
+ * AudioManager.disconnectAudioPatch()
+ * It contains the list of source and sink AudioPortConfig showing audio port configurations
+ * being connected.
+ * @hide
+ */
+public class AudioPatch {
+
+    private final AudioHandle mHandle;
+    private final AudioPortConfig[] mSources;
+    private final AudioPortConfig[] mSinks;
+
+    AudioPatch(AudioHandle patchHandle, AudioPortConfig[] sources, AudioPortConfig[] sinks) {
+        mHandle = patchHandle;
+        mSources = sources;
+        mSinks = sinks;
+    }
+
+    /**
+     * Retrieve the list of sources of this audio patch.
+     */
+    public AudioPortConfig[] sources() {
+        return mSources;
+    }
+
+    /**
+     * Retreive the list of sinks of this audio patch.
+     */
+    public AudioPortConfig[] sinks() {
+        return mSinks;
+    }
+}
diff --git a/media/java/android/media/AudioPort.java b/media/java/android/media/AudioPort.java
new file mode 100644
index 0000000..9aeddef
--- /dev/null
+++ b/media/java/android/media/AudioPort.java
@@ -0,0 +1,174 @@
+/*
+ * 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.media;
+
+
+/**
+ * An audio port is a node of the audio framework or hardware that can be connected to or
+ * disconnect from another audio node to create a specific audio routing configuration.
+ * Examples of audio ports are an output device (speaker) or an output mix (see AudioMixPort).
+ * All attributes that are relevant for applications to make routing selection are decribed
+ * in an AudioPort,  in particular:
+ * - possible channel mask configurations.
+ * - audio format (PCM 16bit, PCM 24bit...)
+ * - gain: a port can be associated with one or more gain controllers (see AudioGain).
+ *
+ * This object is always created by the framework and read only by applications.
+ * A list of all audio port descriptors currently available for applications to control
+ * is obtained by AudioManager.listAudioPorts().
+ * An application can obtain an AudioPortConfig for a valid configuration of this port
+ * by calling AudioPort.buildConfig() and use this configuration
+ * to create a connection between audio sinks and sources with AudioManager.connectAudioPatch()
+ *
+ * @hide
+ */
+public class AudioPort {
+
+    /**
+     * For use by the audio framework.
+     */
+    public static final int ROLE_NONE = 0;
+    /**
+     * The audio port is a source (produces audio)
+     */
+    public static final int ROLE_SOURCE = 1;
+    /**
+     * The audio port is a sink (consumes audio)
+     */
+    public static final int ROLE_SINK = 2;
+
+    /**
+     * audio port type for use by audio framework implementation
+     */
+    public static final int TYPE_NONE = 0;
+    /**
+     */
+    public static final int TYPE_DEVICE = 1;
+    /**
+     */
+    public static final int TYPE_SUBMIX = 2;
+    /**
+     */
+    public static final int TYPE_SESSION = 3;
+
+
+    AudioHandle mHandle;
+    private final int mRole;
+    private final int[] mSamplingRates;
+    private final int[] mChannelMasks;
+    private final int[] mFormats;
+    private final AudioGain[] mGains;
+    private AudioPortConfig mActiveConfig;
+
+    AudioPort(AudioHandle handle, int role, int[] samplingRates, int[] channelMasks,
+            int[] formats, AudioGain[] gains) {
+        mHandle = handle;
+        mRole = role;
+        mSamplingRates = samplingRates;
+        mChannelMasks = channelMasks;
+        mFormats = formats;
+        mGains = gains;
+    }
+
+    AudioHandle handle() {
+        return mHandle;
+    }
+
+    /**
+     * Get the audio port role
+     */
+    public int role() {
+        return mRole;
+    }
+
+    /**
+     * Get the list of supported sampling rates
+     * Empty array if sampling rate is not relevant for this audio port
+     */
+    public int[] samplingRates() {
+        return mSamplingRates;
+    }
+
+    /**
+     * Get the list of supported channel mask configurations
+     * (e.g AudioFormat.CHANNEL_OUT_STEREO)
+     * Empty array if channel mask is not relevant for this audio port
+     */
+    public int[] channelMasks() {
+        return mChannelMasks;
+    }
+
+    /**
+     * Get the list of supported audio format configurations
+     * (e.g AudioFormat.ENCODING_PCM_16BIT)
+     * Empty array if format is not relevant for this audio port
+     */
+    public int[] formats() {
+        return mFormats;
+    }
+
+    /**
+     * Get the list of gain descriptors
+     * Empty array if this port does not have gain control
+     */
+    public AudioGain[] gains() {
+        return mGains;
+    }
+
+    /**
+     * Get the gain descriptor at a given index
+     */
+    AudioGain gain(int index) {
+        return mGains[index];
+    }
+
+    /**
+     * Build a specific configuration of this audio port for use by methods
+     * like AudioManager.connectAudioPatch().
+     * @param channelMask The desired channel mask. AudioFormat.CHANNEL_OUT_DEFAULT if no change
+     * from active configuration requested.
+     * @param format The desired audio format. AudioFormat.ENCODING_DEFAULT if no change
+     * from active configuration requested.
+     * @param gain The desired gain. null if no gain changed requested.
+     */
+    public AudioPortConfig buildConfig(int samplingRate, int channelMask, int format,
+                                        AudioGainConfig gain) {
+        return new AudioPortConfig(this, samplingRate, channelMask, format, gain);
+    }
+
+    /**
+     * Get currently active configuration of this audio port.
+     */
+    public AudioPortConfig activeConfig() {
+        return mActiveConfig;
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || !(o instanceof AudioPort)) {
+            return false;
+        }
+        AudioPort ap = (AudioPort)o;
+        return mHandle.equals(ap.handle());
+    }
+
+    @Override
+    public int hashCode() {
+        return mHandle.hashCode();
+    }
+}
+
diff --git a/media/java/android/media/AudioPortConfig.java b/media/java/android/media/AudioPortConfig.java
new file mode 100644
index 0000000..5dc768d
--- /dev/null
+++ b/media/java/android/media/AudioPortConfig.java
@@ -0,0 +1,93 @@
+/*
+ * 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.media;
+
+/**
+ * An AudioPortConfig contains a possible configuration of an audio port chosen
+ * among all possible attributes described by an AudioPort.
+ * An AudioPortConfig is created by AudioPort.buildConfiguration().
+ * AudioPorts are used to specify the sources and sinks of a patch created
+ * with AudioManager.connectAudioPatch().
+ * Several specialized versions of AudioPortConfig exist to handle different categories of
+ * audio ports and their specific attributes:
+ * - AudioDevicePortConfig for input (e.g micropohone) and output devices (e.g speaker)
+ * - AudioMixPortConfig for input or output streams of the audio framework.
+ * @hide
+ */
+
+public class AudioPortConfig {
+    final AudioPort mPort;
+    private final int mSamplingRate;
+    private final int mChannelMask;
+    private final int mFormat;
+    private final AudioGainConfig mGain;
+
+    // mConfigMask indicates which fields in this configuration should be
+    // taken into account. Used with AudioSystem.setAudioPortConfig()
+    // framework use only.
+    static final int SAMPLE_RATE  = 0x1;
+    static final int CHANNEL_MASK = 0x2;
+    static final int FORMAT       = 0x4;
+    static final int GAIN         = 0x8;
+    int mConfigMask;
+
+    AudioPortConfig(AudioPort port, int samplingRate, int channelMask, int format,
+            AudioGainConfig gain) {
+        mPort = port;
+        mSamplingRate = samplingRate;
+        mChannelMask = channelMask;
+        mFormat = format;
+        mGain = gain;
+        mConfigMask = 0;
+    }
+
+    /**
+     * Returns the audio port this AudioPortConfig is issued from.
+     */
+    public AudioPort port() {
+        return mPort;
+    }
+
+    /**
+     * Sampling rate configured for this AudioPortConfig.
+     */
+    public int samplingRate() {
+        return mSamplingRate;
+    }
+
+    /**
+     * Channel mask configuration (e.g AudioFormat.CHANNEL_CONFIGURATION_STEREO).
+     */
+    public int channelMask() {
+        return mChannelMask;
+    }
+
+    /**
+     * Audio format configuration (e.g AudioFormat.ENCODING_PCM_16BIT).
+     */
+    public int format() {
+        return mFormat;
+    }
+
+    /**
+     * The gain configuration if this port supports gain control, null otherwise
+     * @see AudioGainConfig.
+     */
+    public AudioGainConfig gain() {
+        return mGain;
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index 6246e05..fbe76f9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -93,7 +93,7 @@
     public static final String TAG = "StatusBar";
     public static final boolean DEBUG = false;
     public static final boolean MULTIUSER_DEBUG = false;
-    private static final boolean USE_NOTIFICATION_LISTENER = false;
+    private static final boolean USE_NOTIFICATION_LISTENER = true;
 
     protected static final int MSG_SHOW_RECENT_APPS = 1019;
     protected static final int MSG_HIDE_RECENT_APPS = 1020;
diff --git a/policy/src/com/android/internal/policy/impl/PhoneWindow.java b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
index 2fea785..6b0095a 100644
--- a/policy/src/com/android/internal/policy/impl/PhoneWindow.java
+++ b/policy/src/com/android/internal/policy/impl/PhoneWindow.java
@@ -3179,7 +3179,9 @@
                         com.android.internal.R.attr.dialogTitleDecorLayout, res, true);
                 layoutResource = res.resourceId;
             } else if ((features & (1 << FEATURE_ACTION_BAR)) != 0) {
-                layoutResource = com.android.internal.R.layout.screen_action_bar;
+                layoutResource = a.getResourceId(
+                        com.android.internal.R.styleable.Window_windowActionBarFullscreenDecorLayout,
+                        com.android.internal.R.layout.screen_action_bar);
             } else {
                 layoutResource = com.android.internal.R.layout.screen_title;
             }
diff --git a/services/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index bc34e0ef..0f24ff6 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -186,7 +186,7 @@
         // had to fallback to a different runtime because it is
         // running as root and we need to be the system user to set
         // the property. http://b/11463182
-        SystemProperties.set("persist.sys.dalvik.vm.lib.1", VMRuntime.getRuntime().vmLibrary());
+        SystemProperties.set("persist.sys.dalvik.vm.lib.2", VMRuntime.getRuntime().vmLibrary());
 
         // Enable the sampling profiler.
         if (SamplingProfilerIntegration.isEnabled()) {
diff --git a/telecomm/java/android/telecomm/package.html b/telecomm/java/android/telecomm/package.html
new file mode 100644
index 0000000..1c9bf9d
--- /dev/null
+++ b/telecomm/java/android/telecomm/package.html
@@ -0,0 +1,5 @@
+<html>
+<body>
+    {@hide}
+</body>
+</html>