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